- PVSM.RU - https://www.pvsm.ru -
Недавно Крис Койер отвечал на вопросы читателей Smashing Magazine. Один из вопросов [1] был о том, как распознать код CSS с «душком»:
Как можно определить, что ваш CSS пованивает? Какие признаки указывают на то, что код неоптимален или что разработчик писал его спустя рукава? На что вы смотрите в первую очередь, чтобы определить, плох или хорош код?
Я подумал, что могу расширить и дополнить ответ Криса исходя из собственного опыта.
Я работаю в BSkyB [2]. Я делаю большие сайты — над последним из них я тружусь уже больше года. Плохой код CSS доставляет мне очень много проблем. Когда занимаешься одним сайтом месяцами, ты просто не можешь себе позволить плохой код, и его обязательно надо исправлять.
Я хочу поделиться несколькими вещами, на которые я обращаю внимание прежде всего, чтобы составить впечатление о качестве, сопровождаемости и чистоте кода CSS.
Любые правила CSS, которые отменяют ранее установленные стили (кроме случая сброса стилей) — это тревожный звоночек. Каскадные таблицы стилей по определению должны наследовать предыдущим определениям и дополнять их, а не отменять.
Любое определение вроде:
border-bottom:none;
padding:0;
float:none;
margin-left:0;
обычно не значит ничего хорошего. Если вам приходится обнулять border
, то, скорее всего вы слишком рано его установили. Это трудно объяснить, поэтому приведу пример:
h2{
font-size:2em;
margin-bottom:0.5em;
padding-bottom:0.5em;
border-bottom:1px solid #ccc;
}
Здесь мы задаём элементам h2
не только размер шрифта и отступы, но и поля, и подчёркивание снизу, чтобы визуально отделить заголовок от остального контента. Но, очень может быть, что в другом месте нам не понадобятся ни поля, ни подчёркивание. Возможно, мы напишем что-то вроде:
h2{
font-size:2em;
margin-bottom:0.5em;
padding-bottom:0.5em;
border-bottom:1px solid #ccc;
}
.no-border{
padding-bottom:0;
border-bottom:none;
}
Теперь у нас уже 10 строк кода и уродливое имя класса. Гораздо лучше будет сделать так:
h2{
font-size:2em;
margin-bottom:0.5em;
}
.headline{
padding-bottom:0.5em;
border-bottom:1px solid #ccc;
}
8 строк, никакой отмены стилей и красивое, осмысленное имя класса.
Продвигаясь вниз по файлу стилей, добавляйте правила, а не отнимайте. Если вам приходится отменять ранее установленные стили, скорее всего вы добавили их слишком рано.
Представьте себе CSS-файл на десяток тысяч строк с подобными отменами стилей. Куча лишнего кода! Постепенно добавляйте новые определения поверх старых, более простых, не начинайте сооружать слишком сложные правила слишком рано, иначе вы напишете гораздо больше кода, а делать он будет гораздо меньше.
Когда я вижу, что какое-то правило отменяет предыдущее, я почти наверняка знаю, что стили организованы неправильно и нуждаются в переработке.
Их я особенно ненавижу! Магическое число — это бессмысленное значение, которое используется потому, что оно «просто работает». Например:
.site-nav{
/* [styles] */
}
.site-nav > li:hover .dropdown{
position:absolute;
top:37px;
left:0;
}
top:37px;
— это магическое число. Единственная причина, по которой оно здесь — так получилось, что элементы списка имеют 37 пикселей в высоту, и выпадающие подменю должны появляться внизу элемента меню.
Проблема в том, что эти 37 пикселей — чистая случайность, и на эту константу совершенно нельзя положиться. Что если кто-то изменит размер шрифта в пункте меню, и он будет иметь 29, а не 37 пикселей в высоту? Что если в Chrome пункт меню будет иметь 37 пикселей высоту, а в IE — 36? Это число работает только в одном конкретном случае.
Никогда, никогда не используйте значения которые «просто работают». В предыдущем примере гораздо лучше было бы написать top:100%;
вместо top:37px;
И это не единственная проблема с магическими числами. Кроме ненадёжности они создают ещё и проблему коммуникации. Как другой разработчик сможет понять откуда взялось это число? Если ваш код больше и сложнее приведённого выше примера, и какое-то из магических чисел вдруг перестало работать, вы столкнётесь с тем, что:
Магические числа — это плохо. Они быстро устаревают, они мешают другим разработчикам, их нельзя объяснить и на них нельзя положиться.
Нет ничего хуже, чем наткнуться на такое необъяснимое число в чужом коде. Зачем оно здесь? Что оно значит? Можно ли его трогать или не стоит? Я задаю эти вопросы всякий раз, как вижу такое число. И самый главный вопрос: «Как можно добиться такого же результата без магии?»
Бегите от магических чисел как от чумы!
Примерно вот такие:
ul.nav{}
a.button{}
div.header{}
Это селекторы, в которые добавлены совершенно лишние уточнения. Они плохи потому что:
На самом деле их можно (и нужно) было бы записать так:
.nav{}
.button{}
.header{}
Вот теперь можно применить .nav
к ol
, .button
к input
и быстро заменить div
с классом .header
на элемент header
, когда будем приводить сайт в соответствие с HTML5.
Хотя производительность браузера страдает от таких селекторов не очень сильно, она всё же страдает. Зачем заставлять его перебирать все элементы a
в поисках класса .button
, если можно ограничиться одним лишь классом? Вот ещё более экстремальные примеры:
ul.nav li.active a{}
div.header a.logo img{}
.content ul.features a.butto
Все они могут быть сильно сокращены или переписаны:
.nav .active a{}
.logo > img {}
.features-button{}
Каждый раз, когда я натыкаюсь на чересчур подробные селекторы, я пытаюсь выяснить, почему они заданы именно так, и нельзя ли их сократить.
Так же как и магические числа, они не сулят ничего хорошего. Вот пример:
h1{
font-size:24px;
line-height:32px;
}
Гораздо лучше было бы написать: line-height:1.333;
Интерльиньяж всегда лучше задавать относительно, чтобы код был гибче. При изменении размера шрифта он будет меняться автоматически. А если вы зададите его в пикселях, то вам придётся писать что-то вроде этого:
h1{
font-size:24px;
line-height:32px;
}
/**
* Main site `h1`
*/
.site-title{
font-size:36px;
line-height:48px;
}
И так каждый раз, когда изменится размер шрифта заголовка. Вот так гораздо лучше:
h1{
font-size:24px;
line-height:1.333;
}
/**
* Main site `h1`
*/
.site-title{
font-size:36px;
}
Вроде бы, разница невелика, но в крупном проекте она может иметь большое значение.
Кстати, это относится не только к line-height
. Практически любое жестко вписанное в код абсолютное значение должно вызывать подозрение.
Единственный случай, когда действительно имеет смысл захардкодить абсолютное значение — это в случае работы со вещами, которые всегда должны иметь определённый размер, например, спрайтами.
Это один из крайних частных случаев жёстко заданных магических чисел и некоторых других приёмов, которые используются, чтобы заставить вёрстку работать:
.foo{
margin-left:-3px;
position:relative;
z-index:99999;
height:59px;
float:left;
}
Это ужасный стиль! Все эти уродливые правила наворочены с единственной целью — запихнуть элемент на нужное место любой ценой. Такой код говорит либо об очень плохо спроектированной вёрстке, либо о недостаточном понимании того, как работает блочная модель CSS, либо о том и другом одновременно.
Если вы хорошо продумали вёрстку и разбираетесь в блочной модели, вам вряд ли придётся использовать грубую силу. Если я вижу подобный код, я сразу стараюсь разобраться, в чём проблема, и не надо ли вернуться на несколько шагов назад, чтобы избавиться от необходимости писать такие костыли.
Под опасными селекторами я понимаю такие, которые намного шире, чем необходимо.Вот самый простой и очевидный пример такого селектора:
div{
background-color:#ffc;
padding:1em;
}
Зачем, зачем накрывать каждый div
на странице этой ковровой бомбардировкой? Зачем кому-нибудь может понадобиться селектор вроде aside{}
? Или header{}
, или ul{}
? Такие селекторы намного, намного шире чем необходимо, и ведут к тому, что нам придется отменять стили, о чём мы уже говорили.
Давайте рассмотрим пример с header{}
более подробно. Многие используют этот элемент, чтобы создать шапку страницы, что совершенно правильно. Но если вы пишете стили для него вот так:
header{
padding:1em;
background-color:#BADA55;
color:#fff;
margin-bottom:20px;
}
то это уже совсем не так правильно. Элемент header
вовсе не обязательно подразумевает шапку всей страницы, он может использоваться несколько раз в разных контекстах. Гораздо лучше использовать класс, например .site-header{}
.
Задавать такие подробные стили для такого общего селектора очень опасно. Они просочатся в совершенно непредсказуемые места, как только вы начнёте повторно использовать этот элемент.
Убедитесь, что ваши селекторы бьют точно в цель [3].
Вот ещё пример:
ul{
font-weight:bold;
}
header .media{
float:left;
}
Когда я вижу, как стили применяются к элементу или к сильно обобщённому классу, как в этом примере, я начинаю паниковать. Я знаю, что они чересчур универсальны и у меня будут проблемы. Эти стили могут быть унаследованы в таких местах, в которых это будет совершенно нежелательно, и мне придётся их отменять.
Использовать !important
можно. И это действительно важный инструмент. Тем не менее, его стоит использовать с умом.
!important
надо использовать проактивно, а не реактивно.
Это значит, что его можно использовать тогда, когда вы абсолютно уверены, что вам всегда будет нужно, чтобы это стиль имел приоритет, и вы знаете об этом заранее.
Например, в уверены в том, что вы всегда хотите видеть ошибки красными:
.error-text{
color:#c00!important;
}
Даже если сообщение об ошибке будет выведено внутри блока, в котором цвет текста синий, мы можем быть уверены, что ошибка останется красной. Мы всегда хотим сообщать об ошибке красным цветом, и поэтому мы сразу пишем !important
.
А вот когда мы используем !important
реактивно, то есть в ответ на возникшую проблему, когда мы запутались и вместо того, чтобы разобраться, прём напролом, тогда это плохо.
Реактивное использование !important
не решает проблему, а только прячет её. Надо лечить болезнь, а не симптомы. Проблема никуда не делась, мы просто перекрыли её сверх-специфичным селектором, тогда как нужно было заняться рефакторингом и архитектурой.
Этот вид «дурного запаха» очень важен при работе в большой команде. Я уже писал о том, что id — это плохо [4], потому что они сильно увеличивают специфичность селекторов. От них нет никакого толку, и их никогда не стоит использовать в CSS. Используйте их, чтобы связать элементы HTML с кодом на JavaScript, но не для того, чтобы задавать их стиль.
Причины этого просты:
Если вам этого мало, то я уже и не знаю, что тут ещё сказать…
Если я вижу id, я тут же стараюсь заменить его классом. Излишняя специфичность селекторов губит большие проекты, поэтому жизненно важно удерживать её как можно более низкой.
Напоследок — маленькое упражнение. Попробуйте элегантно решить эту проблему [6]. Подсказка: так [7] — не элегантно; и так [8] — тоже.
Расплывчатое имя — это такое, которое недостаточно конкретно описывает назначение класса. Представьте себе класс .card
. Что он делает?
Это очень расплывчатое имя, а расплывчатые имена плохи из-за двух главных причин:
Первый пункт очень прост: что означает .card
? Стиль чего он задаёт? Карточки задач в системе управления проектами? Игральную карту в онлайн-казино? Изображение кредитной карты? Трудно сказать, потому что имя слишком туманное. Допустим, мы имеем в виду кредитную карту. Тогда намного лучше назвать класс .сredit-card-image{}
. Да, намного длиннее, но и намного, намного лучше!
Вторая проблема с расплывчатыми именами — их очень легко случайно переопределить. Допустим, вы работаете над сайтом интернет-магазина. Вы используете класс .card
, подразумевая номер кредитки, привязанной к аккаунту. А другой разработчик в это время добавляет возможность купить подарок и приложить к нему карточку с поздравлением. И он тоже называет класс .card
, и пишет для него свои правила, которые конфликтуют с вашими.
Этого легко можно избежать, если использовать более точные имена классов. Классы вроде .card
или .user
слишком туманны. Они малоинформативны и их легко случайно переопределить. Имена классов должны быть точны, насколько возможно.
Итак, мы рассмотрели несколько примеров кода «с душком». Это вещи, о которых надо помнить всегда и избегать их изо всех сил, вернее, только малая их часть, на самом деле их гораздо больше. Работая над крупным проектом, который длится месяцы и годы, жизненно важно держать код в хорошей форме.
Кончено, из каждого правила есть исключения, но к ним нужно подходить индивидуально. В большинстве же случаев, такого кода нужно тщательно избегать.
Автор: ilya42
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/css/21031
Ссылки в тексте:
[1] вопросов: http://coding.smashingmagazine.com/2012/07/13/coding-qa-with-chris-coyier-code-smell-type-grid/
[2] BSkyB: http://en.wikipedia.org/wiki/BSkyB
[3] бьют точно в цель: http://csswizardry.com/2012/07/shoot-to-kill-css-selector-intent/
[4] id — это плохо: http://csswizardry.com/2011/09/when-using-ids-can-be-a-pain-in-the-class/
[5] id в 255 раз специфичнее класса: http://codepen.io/chriscoyier/pen/lzjqh
[6] эту проблему: http://jsfiddle.net/csswizardry/9wGac/
[7] так: http://jsfiddle.net/csswizardry/9wGac/1/
[8] так: http://jsfiddle.net/csswizardry/9wGac/2/
[9] Источник: http://habrahabr.ru/post/160177/
Нажмите здесь для печати.