posted by aqshakirzhan on November 19, 2014

Недавно Крис Койер отвечал на вопросы читателей Smashing Magazine. Один из вопросов был о том, как распознать код CSS с «душком»:

Как можно определить, что ваш CSS пованивает? Какие признаки указывают на то, что код неоптимален или что разработчик писал его спустя рукава? На что вы смотрите в первую очередь, чтобы определить, плох или хорош код?

Я подумал, что могу расширить и дополнить ответ Криса исходя из собственного опыта. Я работаю в BSkyB. Я делаю большие сайты — над последним из них я тружусь уже больше года. Плохой код 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{}. Задавать такие подробные стили для такого общего селектора очень опасно. Они просочатся в совершенно непредсказуемые места, как только вы начнёте повторно использовать этот элемент. Убедитесь, что ваши селекторы бьют точно в цель. Вот ещё пример:

ul{ font-weight:bold; } header .media{ float:left; } 

Когда я вижу, как стили применяются к элементу или к сильно обобщённому классу, как в этом примере, я начинаю паниковать. Я знаю, что они чересчур универсальны и у меня будут проблемы. Эти стили могут быть унаследованы в таких местах, в которых это будет совершенно нежелательно, и мне придётся их отменять.

Реактивное использование !important

Использовать !important можно. И это действительно важный инструмент. Тем не менее, его стоит использовать с умом. !important надо использовать проактивно, а не реактивно. Это значит, что его можно использовать тогда, когда вы абсолютно уверены, что вам всегда будет нужно, чтобы это стиль имел приоритет, и вы знаете об этом заранее. Например, в уверены в том, что вы всегда хотите видеть ошибки красными:

.error-text{ color:#c00!important; } 

Даже если сообщение об ошибке будет выведено внутри блока, в котором цвет текста синий, мы можем быть уверены, что ошибка останется красной. Мы всегда хотим сообщать об ошибке красным цветом, и поэтому мы сразу пишем !important. А вот когда мы используем !important реактивно, то есть в ответ на возникшую проблему, когда мы запутались и вместо того, чтобы разобраться, прём напролом, тогда это плохо. Реактивное использование !important не решает проблему, а только прячет её. Надо лечить болезнь, а не симптомы. Проблема никуда не делась, мы просто перекрыли её сверх-специфичным селектором, тогда как нужно было заняться рефакторингом и архитектурой.

ID

Этот вид «дурного запаха» очень важен при работе в большой команде. Я уже писал о том, что id — это плохо, потому что они сильно увеличивают специфичность селекторов. От них нет никакого толку, и их никогда не стоит использовать в CSS. Используйте их, чтобы связать элементы HTML с кодом на JavaScript, но не для того, чтобы задавать их стиль. Причины этого просты:

  • id можно использовать на странице только один раз;
  • класс можно использовать сколько угодно;
  • большинство правил, применяемых к id можно разбросать по нескольким классам;
  • id в 255 раз специфичнее класса;
  • Это значит, что вам понадобится применить 256 классов к элементу, чтобы перевесить один id.

Если вам этого мало, то я уже и не знаю, что тут ещё сказать… Если я вижу id, я тут же стараюсь заменить его классом. Излишняя специфичность селекторов губит большие проекты, поэтому жизненно важно удерживать её как можно более низкой. Напоследок — маленькое упражнение. Попробуйте элегантно решить эту проблему. Подсказка: так — не элегантно; и так — тоже.

Расплывчатые имена классов

Расплывчатое имя — это такое, которое недостаточно конкретно описывает назначение класса. Представьте себе класс .card. Что он делает? Это очень расплывчатое имя, а расплывчатые имена плохи из-за двух главных причин:

  • вы не сможете догадаться, что оно означает;
  • оно настолько общее, что легко может быть случайно переопределено другим разработчиком.

Первый пункт очень прост: что означает .card? Стиль чего он задаёт? Карточки задач в системе управления проектами? Игральную карту в онлайн-казино? Изображение кредитной карты? Трудно сказать, потому что имя слишком туманное. Допустим, мы имеем в виду кредитную карту. Тогда намного лучше назвать класс .сredit-card-image{}. Да, намного длиннее, но и намного, намного лучше! Вторая проблема с расплывчатыми именами — их очень легко случайно переопределить. Допустим, вы работаете над сайтом интернет-магазина. Вы используете класс .card, подразумевая номер кредитки, привязанной к аккаунту. А другой разработчик в это время добавляет возможность купить подарок и приложить к нему карточку с поздравлением. И он тоже называет класс .card, и пишет для него свои правила, которые конфликтуют с вашими. Этого легко можно избежать, если использовать более точные имена классов. Классы вроде .card или .user слишком туманны. Они малоинформативны и их легко случайно переопределить. Имена классов должны быть точны, насколько возможно.

Заключение

Итак, мы рассмотрели несколько примеров кода «с душком». Это вещи, о которых надо помнить всегда и избегать их изо всех сил, вернее, только малая их часть, на самом деле их гораздо больше. Работая над крупным проектом, который длится месяцы и годы, жизненно важно держать код в хорошей форме. Кончено, из каждого правила есть исключения, но к ним нужно подходить индивидуально. В большинстве же случаев, такого кода нужно тщательно избегать. http://habrahabr.ru

Leave a Comment

Fields with * are required.