Десять заповедей логичных файлов стилей

Перевод статьи The ten commandments of sane style sheets с сайта benfrain.com, автор — Бен Фрейн.

Десять заповедей

  1. Да будет у тебя единственное место в коде для каждого ключевого селектора
  2. Не вкладывай (ежели не вкладываешь медиавыражений, переопределений, либо сие воистину необходимо)
  3. Не используй селекторов по ID (даже ежели мнишь, что сие необходимо)
  4. Не пиши браузерных префиксов в исходных файлах стилей
  5. Используй переменные для размеров, цветов и z-индекса
  6. Всегда первыми пиши правила для мобильных устройств (сторонись max-width)
  7. Используй миксины для стеков шрифтов
  8. Комментируй все магические числа и браузерные хаки
  9. Не встраивай изображений в код
  10. Не пиши сложного CSS там, где простой CSS достаточен

Блаженны соблюдающие сии правила, ибо они наследуют логичные таблицы стилей.

Аминь.

Почему десять заповедей?

CSS по природе глобален. Пока невозможно ограничить правила конкретными областями интерфейса. Поэтому поддерживать любой разросшийся CSS-код может стать трудно. Глобальная природа CSS означает, что стили могут задеть не только нужный целевой объект, но и другие элементы. Более того, в больших CSS-файлах каскадность стилей начинает порождать нежелательные эффекты, когда правила в одной части CSS-файла могут влиять (или не влиять) на другие правила.

CSS также можно писать так, что он будет зависеть от структуры DOM. Это тоже негибко и чревато проблемами. Селекторы потомков, селекторы по ID и слишком специфичные селекторы — всё это ведет к тому, что CSS становится трудно поддерживать, о нем приходится постоянно задумываться, и он легко ломается при изменениях DOM.

Попытаться решить эту проблему можно двумя способами. Первый — строго соблюдать систему именования на базе CSS-классов. Это подробно описано в других местах. Второй — следовать неким правилам, которые позволяют сделать файлы стилей более надежными и легкими в поддержке.

Инструментарий

Добиться того, чтобы стили стало легче поддерживать, нам поможет PostCSS, инструмент для работы со стилями, позволяющий манипулировать ими с помощью JavaScript. Любопытные могут заглянуть за дополнительной информацией сюда: https://github.com/postcss/postcss.

PostCSS дает возможность пользоваться расширенным синтаксисом CSS. Этим можно воспользоваться для облегчения поддержки наших исходных файлов стилей.

Благодаря PostCSS у нас в руках оказываются:

  • переменные
  • миксины (аналог макросов для опред. установок, напр. шрифтов)
  • ссылка на ключевой селектор с помощью символа амперсанда (&)
  • возможность писать циклы для больших наборов правил (напр., 100 вариантов по-разному раскрашенных заголовков)

На практике PostCSS близок по функциональности к CSS-препроцессорам вроде Sass, LESS или Stylus.

Отличие его — в модульности и расширяемости. Вместо того, чтобы «запихивать всё одним куском», как вышеупомянутые препроцессоры, использование PostCSS позволяет нам более избирательно подходить к выбору абстракций и тому, как нам анализировать и поддерживать эти абстракции с точки зрения написания кода. Он также позволяет расширять наши стилевые абстракции, если мы того пожелаем.

Кроме того, с ним мы можем проводить статический анализ (линтинг) кода исходных файлов стилей, и не пропускать сборки, в которые попал неудачно написанный код.

Обоснование

Мы хотим, чтобы создаваемый нами CSS не страдал от излишней специфичности, засоренности ненужными префиксами, дефицита комментариев и избытка «магических» чисел.

10 правил, которые описаны ниже, считаются важнейшими для того, чтобы достичь этой цели.

Термины, использованные во всей статье:

  • переопределение: ситуация, когда значения для ключевого селектора намеренно корректируются с использованием наследования
  • ключевой селектор: крайний правый селектор в любом CSS-правиле
  • префиксы: префиксы для отдельных браузеров, напр. -webkit-transform
  • исходные файлы стилей: файлы, в которых мы пишем правила
  • CSS: результирующий CSS-файл, который генерируют наши инструменты и который в итоге достается браузеру.

Развернутая информация по десяти заповедям

У каждой из 10 заповедей есть свое обоснование. Сейчас мы рассмотрим их все.

1. Да будет у тебя единственное место в коде для каждого ключевого селектора

В исходных файлах стилей ключевой селектор должен быть написан только один раз.

Это позволит нам при поиске по коду находить то единственное место, которое зависит от нашего селектора. Благодаря расширенному CSS-синтаксису, ВСЁ, что происходит с этим ключевым селектором, можно инкапсулировать в один блок правил.

Переопределения для ключевого селектора обрабатываются через вложенность и ссылку на ключевой селектор с помощью «родительского» селектора. Подробнее об этом чуть позже.

Рассмотрим такой пример:

.key-Selector {
    width: 100%;
    @media (min-width: $M) {
        width: 50%;
    }
    .an-Override_Selector & {
        color: $color-grey-33;
    }
}

В итоговом CSS из этого получится следующее:

.key-Selector {
  width: 100%;
}

@media (min-width: 768px) {
  .key-Selector {
    width: 50%;
  }
}

.an-Override_Selector .key-Selector {
  color: #333;
}

В исходных файлах стилей ключевой селектор (.key-Selector) ни разу не повторяется на корневом уровне. Следовательно, с точки зрения поддержки, нам достаточно поискать в коде .key-Selector — и мы найдем всё, что происходит с этим ключевым селектором, описанное в одном месте.

  • Что, если нам понадобится отобразить его по-другому при другом размере экрана?
  • Что случится, если он окажется внутри контейнера containerX?
  • Что будет, если ему добавить тот или другой класс с помощью JavaScript?

Во всех этих случаях всё, что может случиться с этим ключевым селектором, будет вложено в один блок правил. Давайте рассмотрим переопределения подробнее.

Работа с переопределениями

В предыдущем примере было показано, как обращаться с переопределением для ключевого селектора. Мы вкладываем переопределяющий селектор в блок правил для ключевого селектора и ссылаемся на родителя с помощью символа &. Символ &, как и в языке Sass — родительский селектор. Можете рассматривать его как аналог this. в JavaScript.

Совет: для тестирования правил с родительским селектором я рекомендую http://sassmeister.com

Стандартное переопределение

Рассмотрим пример:

.ip-Carousel {
    font-size: $text13;
    /* Переопределение для случая, когда этот ключевой селектор находится внутри элемента ip-HomeCallouts */
    .ip-HomeCallouts & {
        font-size: $text15;
    }
}

В результирующем CSS получится следующее:

.ip-Carousel {
  font-size: 13px;
}

.ip-HomeCallouts .ip-Carousel {
  font-size: 15px;
}

Это увеличит размер шрифта для ip-Carousel, когда он оказывается внутри элемента с классом ip-HomeCallouts.

Переопределение с добавочным классом для того же элемента

Возьмем другой пример, что если нам понадобится переопределить стиль элемента, если у него будет дополнительный класс? Нужно сделать примерно так:

.ip-Carousel {
    background-color: $color-green;
    &.ip-ClassificationHeader {
        background-color: $color-grey-a7;
    }
}

В итоговом CSS получится:

.ip-Carousel {
  background-color: #14805e;
}

.ip-Carousel.ip-ClassificationHeader {
  background-color: #a7a7a7;
}

Опять же, переопределение заключено в блок правил для ключевого селектора

Переопределение внутри другого класса при наличии добавочного класса

Наконец, давайте посмотрим, как нам быть, если нужно переопределить стиль для ключевого селектора, когда он находится внутри другого элемента и вдобавок у него самого есть дополнительный класс:

.ip-Carousel {
    background-color: $color-green;
    .home-Container &.ip-ClassificationHeader {
        background-color: $color-grey-a7;
    }
}

В CSS это будет выглядеть следующим образом:

.ip-Carousel {
  background-color: #14805e;
}

.home-Container .ip-Carousel.ip-ClassificationHeader {
  background-color: #a7a7a7;
}

Тут мы использовали родительский селектор, чтобы сослаться на наш ключевой селектор между переопределением по вышестоящему элементу (.home-Container) и другому классу одновременно (.ip-ClassificationHeader).

Переопределение с медиавыражениями

Наконец, рассмотрим переопределения с медиавыражениями. Вот пример:

.key-Selector {
    width: 100%;
    @media (min-width: $M) {
        width: 50%;
    }
}

В CSS это будет так:

.key-Selector {
  width: 100%;
}

@media (min-width: 768px) {
  .key-Selector {
    width: 50%;
  }
}

Снова, все возможные варианты заключены в одном и том же правиле. Обратите внимание на переменную для ширины в медиавыражении. Мы скоро до этого дойдем.

Все без исключения медиавыражения нужно включать одним и тем же образом. Вот пример посложнее:

.key-Selector {
    width: 100%;
    @media (min-width: $M) and (max-width: $XM) and (orientation: portrait) {
        width: 50%;
    }
    @media (min-width: $L) {
        width: 75%;
    }
}

В CSS это будет выглядеть так:

.key-Selector {
  width: 100%;
}

@media (min-width: 768px) and (max-width: 950px) and (orientation: portrait) {
  .key-Selector {
    width: 50%;
  }
}

@media (min-width: 1200px) {
  .key-Selector {
    width: 75%;
  }
}

Насмотревшись на всё это вложение переопределений, вы можете подумать, почему бы не вкладывать и дочерние элементы? Это ошибка. Большая ошибка. Так делать в корне неправильно. Сейчас мы рассмотрим, почему.

2. Не вкладывай (ежели не вкладываешь медиавыражений, переопределений, либо сие воистину необходимо)

Ключевой селектор в CSS — крайний правый в любом правиле. Это тот селектор, к которому применяются свойства/значения в фигурных скобках.

Мы хотим, чтобы наши правила CSS были максимально «плоскими», насколько можно. Нам НЕ нужны другие селекторы перед ключевым (или любым DOM-элементом), если в них нет абсолютной необходимости для переопределения стилей ключевого селектора по умолчанию. Добавление дополнительных селекторов и привязка к типу элемента (напр. h1.yes-This_Selector)

  • создает ненужную добавочную специфичность
  • усложняет поддержку, вынуждая делать переопределения еще более специфичными
  • без нужды раздувает код итогового CSS
  • в случае типа элемента — привязывает правило к определенному тегу

Например, предположим, что у нас есть CSS-правило вроде этого:

#notMe .or-me [data-thing="nope"] .yes-This_Selector {
    width: 100%;
}

В этом примере ключевой селектор — yes-This_Selector. Если нужно, чтобы соотв. свойства/значения применялись к нему в любых обстоятельствах, нужно сделать правило попроще.

Чтобы упростить предыдущий пример, если мы всего лишь хотим обратиться к ключевому селектору, нам понадобилось бы правило наподобие такого:

.yes-This_Selector {
    width: 100%;
}

Не вкладывайте потомков внутри правила

Допустим, у нас есть кнопка запуска видео внутри элемента-обертки. Рассмотрим разметку:

<div class="med-Video">
            <div class="med-Video_Play">Play</div>
</div>

Давайте добавим немного базовых стилей для обертки:

.med-Video {
    position: absolute;
    background-color: $color-black;
}

Теперь нам нужно отпозиционировать кнопку Play внутри обертки. У вас может быть соблазн сделать так:

ОСТОРОЖНО: ПРИМЕР НЕПРАВИЛЬНОГО КОДА

.med-Video {
    position: absolute;
    background-color: $color-black;
    /* Центрируем кнопку Play */
    .med-Video_Play {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
}

Это превратится в такой CSS (браузерные префиксы убраны ради краткости):

.med-Video {
  position: absolute;
  background-color: #000;
  /* Центрируем кнопку Play */
}

.med-Video .med-Video_Play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

Видите здесь проблему? Мы без всякой необходимости ввели добавочную специфичность для элемента .med-Video_Play.

Это едва заметная иллюстрация. Но важно знать об этой проблеме и избегать ее, мы же не хотим правил вроде такого:

ОСТОРОЖНО: ПРИМЕР НЕПРАВИЛЬНОГО КОДА

.MarketGrid > .PhoneOnlyContainer > .ClickToCallHeader > .ClickToCallHeaderMessage > .MessageHolder > span {
  font-weight: bold;
  padding-right: 5px;
}

Чтобы такого не было, помните: у каждого ключевого селектора — свой блок правил. Переопределения вкладываются, дочерние элементы — нет. Вот тот же пример, переписанный как надо:

.med-Video {

.med-Video {
    position: absolute;
    background-color: $color-black;
}

/* Центрируем кнопку Play */
.med-Video_Play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

В CSS получится такое:

.med-Video {
  position: absolute;
  background-color: #000;
}

/* Центрируем кнопку Play */
.med-Video_Play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

Каждый ключевой селектор специфичен ровно настолько, насколько нужно, не более того.

3. Не используй селекторов по ID (даже ежели мнишь, что сие необходимо)

Ограничения ID-шек в сложных интерфейсах хорошо документированы. Вкратце, они намного специфичнее селекторов по классу — а значит, переопределить их намного сложнее, а также их можно использовать лишь по одному разу на странице, что тоже ограничивает их применимость.

Совет: за подробностями о специфичности обратитесь к http://www.w3.org/TR/CSS21/cascade.html#specificity

Не используйте селекторов по ID в CSS. Они не дают никаких преимуществ перед селекторами по классу и добавляют ненужных проблем.

В практически невероятной ситуации, когда вы ВЫНУЖДЕНЫ использовать ID для выбора элемента, лучше используйте его в селекторе атрибута, чтобы специфичность не повышалась:

[id="Thing"] {
    /* Свойства/значения здесь */
}

4. Не пиши браузерных префиксов в исходных файлах стилей

Нам больше незачем писать в исходных файлах стилей браузерные префиксы для свойств/значений, описанных в спецификациях W3C — спасибо PostCSS и его инструментам. Всю работу с префиксами «автомагически» выполняет инструмент Autoprefixer, который можно настроить так, чтобы он обеспечивал префиксами браузеры/платформы в соответствии с заданным уровнем поддержки.

Например, не делайте так:

ОСТОРОЖНО: ПРИМЕР НЕПРАВИЛЬНОГО КОДА

.ip-Header_Count {
    position: absolute;
    right: $size-full;
    top: 50%;
    -webkit-transform: translateY(-50%);
    -ms-transform: translateY(-50%);
    transform: translateY(-50%);
}

Вместо этого пишите просто:

.ip-Header_Count {
    position: absolute;
    right: $size-full;
    top: 50%;
    transform: translateY(-50%);
}

Это не только упрощает чтение исходных файлов стилей и работу с ними, но означает еще и то, что если мы пожелаем изменить уровень поддержки браузеров, нам достаточно поменять одну-единственную настройку в системе сборки — и список добавляемых префиксов автоматически обновится.

Единственное исключение из этого сценария — нестандартные свойства/значения, которые всё же могут быть полезны. Например, для кинетической прокрутки панелей движением пальца на устройствах с WebKit-браузерами определенные префиксы могут понадобиться и в исходном файле стилей, поскольку они не являются стандартом W3C. Например:

.ui-ScrollPanel {
    -webkit-overflow-scrolling: touch;
}

Или если надо скрыть полосу прокрутки для WebKit:

.ui-Component {
    &::-webkit-scrollbar {
      -webkit-appearance: none;
    }
}

5. Используй переменные для размеров, цветов и z-индекса

Независимо от размера проекта, задавать переменные для размеров, цветов и z-index — насущная необходимость.

Интерфейсы обычно строятся на базе какой-то разновидности сетки или пропорции. Поэтому размеры должны отталкиваться от заданных величин и логичных схем на их основе. Например, вот система размеров и их вариаций с базовой величиной 11px, в виде переменных:

$size-full: 11px;
$size-half: 5.5px;
$size-quarter: 2.75px;
$size-double: 22px;
$size-treble: 33px;
$size-quadruple: 44px;

Для разработчика использование переменных дает дополнительные выгоды. Например, реже приходится брать «пипеткой» цвета составных элементов. Оно также помогает приводить дизайны к единообразию.

Скажем, если проект использует только 13-, 15- и 22-пиксельные шрифты, и вдруг возникает требование добавить 14-пиксельный текст, благодаря переменным проще привести это к одному виду. В данном случае, должен ли шрифт быть 13- или 15-пиксельным, раз 14 нигде больше не используется? Это позволяет разработчикам вовремя сообщать дизайнерам о возможных несоответствиях в дизайне.

То же самое справедливо и для значений цветов. Допустим, у нас есть переменная для значения #333. Мы можем записать ее в виде переменной вот так:

$color-grey-33: #333;

На первый взгляд кажется нелепым писать имя переменной, когда 16-ричное значение короче. Однако, опять же, переменные не дают нежелательным вариантам (напр. #323232) проникать в код и помогают обнаруживать в коде «опасные места».

Не менее важно использовать переменные при модификациях цветов. Чтобы достичь желаемого, пользуйтесь цветовыми функциями для переменных. Допустим, нам нужно сделать цвет #333 полупрозрачным.

Это можно сделать в исходном файле стилей примерно так:

.ip-Header {
    background-color: color($color-grey-33 a(.5));
}

PostCSS может предоставить полифилл для цветовых функций W3C (https://drafts.csswg.org/css-color/#modifying-colors)

и из предыдущего примера получится такой CSS:

.ip-Header {
    background-color: rgba(51, 51, 51, 0.5);
}

В этом примере мы применили цветовую функцию alpha. Мы взяли функцию color(), передали ей цвет, которым собираемся манипулировать, и указали нужную манипуляцию (в данном случае alpha).

Работать с переменными поначалу кажется сложнее, но тем, кто будет править этот код в будущем, это поможет не запутаться, где каким цветом они манипулируют.

Столь же важно использовать переменные для z-index. Это обеспечивает определенную логику, когда дело касается контекстов наложения. Не должно быть потребности в z-index:999 и т.п. Вместо этого воспользуйтесь небольшим количеством типовых значений в виде переменных. Вот подходящие переменные для z-index:

$zi-highest: 50;
$zi-high: 40;
$zi-medium: 30;
$zi-low: 20;
$zi-lowest: 10;
$zi-ground: 0;
$zi-below-ground: -1;

6. Всегда первыми пиши правила для мобильных устройств (сторонись max-width)

В любой адаптивности мы хотим, чтобы наши стили соответствовали духу подхода «сначала мобильные». Следовательно, в корневом правиле должны быть те свойства и значения, что применяются для наименьших экранов (напр. мобильников). Затем с помощью медиавыражений мы переопределяем эти стили по мере необходимости.

Рассмотрим такой пример:

.med-Video {
    position: relative;
    background-color: $color-black;
    font-size: $text13;
    line-height: $text15;
    /* На экранах среднего размера мы хотим увеличить текст */
    @media (min-width: $M) {
        font-size: $text15;
        line-height: $text18;
    }
    /* Текст и высота строки опять меняются для еще больших экранов */
    @media (min-width: $L) {
        font-size: $text18;
        line-height: 1;
    }
}

В CSS получится:

.med-Video {
  position: relative;
  background-color: #000;
  font-size: 13px;
  line-height: 15px;
}

@media (min-width: 768px) {
  .med-Video {
    font-size: 15px;
    line-height: 18px;
  }
}

@media (min-width: 1200px) {
  .med-Video {
    font-size: 18px;
    line-height: 1;
  }
}

Нам нужно лишь поменять размер шрифта и высоту строки для разных размеров экрана, так что только их мы и уточняем. Благодаря использованию min-width (без max-width) в медиавыражении, если бы менять размер шрифта и высоту строки для большего экрана не требовалось, нам вообще не понадобилось бы дополнительных медиавыражений. Медиавыражения нужны, только когда что-то меняется с увеличением размера экрана. Ради этого и не стоит использовать max-width как единственный аргумент в медиавыражениях.

Примечание: пишите медиавыражения с min-width без max-width. Единственное исключение — если вы хотите ограничить некоторые стили промежуточным диапазоном. Например, между границами среднего и большого экранов. Пример:

.med-Video {
    position: relative;
    background-color: $color-black;
    font-size: $text13;
    line-height: $text15;
    /* При размерах от среднего до большого увеличиваем текст */
    @media (min-width: $M) and (max-width: $L) {
        font-size: $text15;
        line-height: $text18;
    }
}

7. Используй миксины для шрифтов

В стеках шрифтов легко запутаться, а составление их — нудное дело. Самый разумный способ справиться со шрифтами — задать самый общий стек шрифтов для body, а затем переопределять это другим стеком по мере необходимости.

Например:

.med-Video {
    position: relative;
    background-color: $color-black;
    font-size: $text13;
    line-height: $text15;
    /* На экранах среднего размера мы хотим увеличить текст */
    @media (min-width: $M) {
        @mixin FontHeadline;
        font-size: $text15;
        line-height: $text18;
    }
}

Для простых стеков шрифтов эту задачу легко решает переменная, так что можно ей и ограничиться. Миксины нужны для более сложных стеков, когда нужно, чтобы определенные стеки применялись в разных ситуациях. Например, пусть даже для основного текста на экранах с низкой плотностью пикселей нужен один шрифт, а для высокой плотности пикселей — другой. Одной переменной такие ситуации не обработать, поэтому по мере надобности вызывается миксин.

8. Комментируй все волшебные числа и браузерные хаки

Все переменные, относящиеся к проекту, должны содержаться в файле variables.css. Если возникает ситуация, когда нужно добавить в исходный файл стилей значение в пикселях, не описанное в variables.css, вы должны реагировать на это как на сигнал опасности. Этот сценарий тоже описан выше. В случае, если нужно добавить в исходный файл стилей «магическое» значение, убедитесь, что его важность поясняется комментарием над соотв. строчкой. Это может показаться лишним во время написания, но подумайте о других, да и о самом себе через 3 месяца. Вот зачем вы добавили этому элементу отрицательный magrin в 17 пикселей?

Пример:

.med-Video {
    position: relative;
    background-color: $color-black;
    font-size: $text13;
    line-height: $text15;
    /*Нужно место для размещения абсолютно позиционированной иконки */
    margin-top: 20px;
}

То же самое относится к хакам для браузеров и устройств. Можете придумать собственный синтаксис, но лично я, когда мне нужно добавить код исключительно ради определенной ситуации, ставлю прямо над кодом хака комментарий, который начинается со строки /*ХХХак:*/. Рассмотрим следующее:

.med-Video {
    background-color: $color-black;
    font-size: $text13;
    line-height: $text15;
    /*ХХХак, необходимый для отображения на всю ширину в Windows Phone 8.1, см. баг SMP-XXX */
    width: 100%;
}

Такие переопределения должны быть как можно ниже в блоке правил. Но всё равно ставьте комментарий. Иначе те, кто будет просматривать код после вас, подумают, что эти строчки не нужны, и удалят их.

9. Не встраивай изображений в код исходных файлов стилей

Пока мы поддерживаем пользователей протокола HTTP (в отличие от HTTP2), во встраивании ресурсов в код есть определенные плюсы. Прежде всего это уменьшает количество HTTP-запросов, нужных для загрузки страницы пользователю. Но встраивать ресурсы в исходные файлы стилей нежелательно.

Взгляните на это:

.rr-Outfit {
    min-height: $size-quadruple;
    background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAAAw1BMVEX///8AAACEhIQAAABYWFgAAAAAAAAAAAB6enomJiYAAAAiIiJ4eHgAAABiYmJgYGAAAACJiYkAAAC0tLR/f3/IyMjHx8e/v7+vr6+fn5+ZmZmUlJSBgYFmZmYiIiIQEBAAAAD////w8PDv7+/i4uLh4eHf39/W1tbS0tLR0dHMzMzHx8fFxcXCwsK/v7+4uLi0tLSvr6+rq6ulpaWfn5+ZmZmQkJCPj498fHxwcHBgYGBAQEAwMDAgICAfHx8QEBAAAAAphWZmAAAAQXRSTlMAESIiMzNEVWZmZneIiKqqu8zM3d3u7u7u7u7u7u7u7u7//////////////////////////////////////////wP/q/8AAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAVdEVYdENyZWF0aW9uIFRpbWUAMjEvNS8xMpVX8IQAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzVxteM2AAAAw0lEQVQYlU2P6VLCUAyFD1KvWFQ2F1ChnLLW2oIs1ZZC8/5PRW4rM+RH5uSbLCeARt2YO2Pq+I+aafUjRs+PplbVzfeQcbyZzoZuSZoBdyKSkQxdOx+SuQKZK/m8BZ7Iia3lT8m6BQy4/NodpYjpb9OiC3i/U+1NfE08iAdIamXACggwzq7BCGgfrIxt8pOsDbjpRu/k+Q/DBWf3auSVq/1Rz55074d16gT0i8pq4JTPOC9MRIqEbzeXfx860eS71yj1GWENHluGjvJwAAAAAElFTkSuQmCC);
}

Как будущий редактор кода догадается, что это за картинка?

Подсказка: если вы натыкаетесь на уже встроенные в код стилей картинки, можно определить, что это, копируя и вставляя данные из url() в адресную строку браузера.

Пусть вместо вас встраиванием картинок занимается инструментарий. Это значит, что в исходных файлах стилей будет не только подсказка, что это может быть за картинка, но и возможность легко заменить эту картинку другой. А встроить картинки можно с помощью команды встраивания. Вот предыдущий пример, переписанный как надо:

.rr-Outfit {
    min-height: $size-quadruple;
    background-image: inline("/path/to-image/relevant-image-name.png");
}

10. Не пиши сложного CSS там, где простого CSS достаточно

Старайтесь писать (и пишите) CSS-код настолько простым, чтобы другим было просто разобраться в нем в будущем. Циклы, миксины и функции желательно сводить к минимуму или использовать в исключительных случаях. В общем случае, если у правила менее 10 вариантов — пишите их «от руки». С другой стороны, если нужно задавать позиции фона для спрайта из 30 картинок, такое лучше доверить инструментарию.

Старайтесь обходиться без миксинов. Злоупотребление миксинами может породить код, слишком отвлеченный от результата. Хотя миксины и нужны для шрифтов или чтобы автоматически генерировать строки, в которых иначе легко ошибиться, других ситуаций, когда они оправданы, не так уж много.

Это стремление к простоте должно распространяться и на способы раскладки макета. Если механизм раскладки с лучшей поддержкой решает ту же задачу с тем же количеством DOM-элементов, что и менее поддерживаемый, выбирайте первый. Однако, если другой механизм раскладки позволяет обойтись меньшим количеством DOM-элементов или дает другие преимущества, просто слишком сложен для понимания или непривычен (да-да, флексбоксы, я думаю о вас), найдите время, чтобы разобраться в возможных преимуществах нового.

Как инструменты помогают соблюдать правила

Правила — ничто, если их можно не соблюдать. В идеале статический анализ кода исходных файлов стилей должен в реальном времени отслеживать их изменения и «отсекать» код, написанный с явным нарушением этих правил.

На момент написания статьи в составе инструментария PostCSS для обратной связи по мере написания исходных стилей используется Stylelint.

«Из коробки» Stylelint может выдавать оповещения в командной строке (и желательно настроить его так, чтобы он не пропускал сборки с некачественным кодом), но есть плагины для Sublime Text и Atom, сообщающие о возможных проблемах в реальном времени. В файл .stylelintrc в репозитории проекта можно внести принятые в команде правила, которые должны гарантированно соблюдаться.

P.S. Это тоже может быть интересно:

10 Комментарии

  1. Саша

    В примере к параграфу «Переопределение с добавочным классом для того же элемента» лишний родительский класс «.home-Container»

    1. SelenIT

      Спасибо! Исправили.

  2. Саша

    Мне понятно, почему не стоит вкладывать вот так:

    .med-Video {
    .med-Video_Play {
    ...
    }
    }

    А так вот тоже не стоит?

    .med-Video {
    &_Play {
    ...
    }
    }

    Странно использовать SASS/LESS/PostCSS только для переменных.

    1. SelenIT

      Насколько я понял автора, это уже «грешновато» относительно 10-й заповеди:). Он призывает к тому, чтобы код был максимально понятен с первого взгляда, а такая структура уже поневоле заставляет задуматься, хотя бы на несколько секунд.

      1. Саша

        Справедливости ради замечу, что я пишу через амперсанд на случай, если класс блока изменится, чтобы не менять его у элементов, и ни разу не сталкивался с тем, чтобы это пригодилось. В крайнем случае множественный курсор или автозамена в Сублайме позволяет все изменить за пару секунд. Попробую без амперсанда собрать проект, сравню впечатления.

        1. SelenIT

          С полноценным БЭМом, на мой взгляд, нарушать эти «заповеди» не страшно, так как в нем за логичностью стилей как раз следит система именования («первый способ решения проблемы запутанности CSS», который Бен упоминает в начале, но в статье не рассматривает). «Заповеди» скорее скорее для того, чтобы не запутаться даже без такой четкой системы.

  3. Александр

    Объясните кто-нибудь почему

    .med-Video {
    position: relative;
    background-color: $color-black;
    font-size: $text13;
    line-height: $text15;
    /* На экранах среднего размера мы хотим увеличить текст */
    @media (min-width: $M) {
    font-size: $text15;
    line-height: $text18;
    }
    /* Текст и высота строки опять меняются для еще больших экранов */
    @media (min-width: $L) {
    font-size: $text18;
    line-height: 1;
    }
    }

    тут не использовать max-width.
    Я привык писать сначала дестоп(обычно заказчик или дизайнер присылает макет дестопа а потом мобилку), а потом max-width’ом дописывать планшет и мобилку.
    А вот уже min-width’ом писать high-resolution.
    Почему это неверно???

    1. SelenIT

      Это принцип Mobile first (сначала мобильные): по умолчанию разместить информацию так, чтобы ей можно было пользоваться даже в одной узкой колонке, а по мере появления дополнительного места — размещать более красиво. Очень логично вписывается в адаптивность и лежит в основе многих «отзывчивых» фреймворков. Есть обоснованное мнение, что при разработке «с нуля» это проще, чем пытаться «развернуть» в колонку уже существующую сложную раскладку. Конечно, в идеале дизайнер тоже должен с самого начала задумываться о мобильном виде, а не вспоминать про него уже перед самой сдачей проекта, и это надо оговаривать в начале разработки.

      В принципе, можно делать адаптивность и без этого (как и нарушать остальные заповеди Бена). Кому-то, возможно, так даже удобнее. Но если проект будет расти и развиваться, поддерживать и расширять его будет проще, придерживаясь стабильных и универсальных принципов.

    2. Саша

      Это «неверно» для новых адаптивных проектов. С принципом mobile first проще разрабатывать. Потому что первый вид, что для мобильных, обычно работает даже в IE7 без дополнительных телодвижений.

      Для не адаптивных проектов разница будет лишь в том, что первые стили у вас будут для всех десктопов, а стили из @media только для избранных.

      1. Саша

        И как заметил выше SelenIT: нарастить c мобильной версии десктопную проще, чем наоборот.

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.