Оглавление

    CSS

    Синтаксис

    • После значения свойства обязательно ставится точка с запятой.
    • Шестнадцатеричное значение цвета сокращается. Для записи используются строчные буквы.
    • Названия тегов и свойств в правилах пишутся строчными буквами.
    • Начальный ноль для значений не сокращается (например, .5 вместо 0.5).
    • Во всех случаях в стилях используются одинарные кавычки. В необязательных случаях кавычки не опускаются.
    • После двоеточия в правилах ставится один пробел (top: 10px;). А перед двоеточием пробел не нужен.
    • После запятых внутри значений rgb(), rgba(), hsl(), hsla() или rect() пробелы ставятся. Это повышает удобочитаемость.
    • До и после комбинатора между селекторами (например, p > a) ставится один пробел.
    • Каждое объявление в правиле пишется на новой строке.
    • Перед открывающейся фигурной скобкой ставится один пробел. После скобки запись идёт с новой строки.
    • Закрывающая фигурная скобка пишется на новой строке и без отступа. Следующее после этого правило отделяется пустой строкой.
    • Единицы измерения не пишутся, там где в них нет необходимости. Например, border: 0.
    • Для проверки CSS-кода используйте stylelint.
    /* 😊 Хорошо */
    .selector,
    .selector-secondary,
    .selector[type="text"] {
      padding: 15px;
      margin-bottom: 15px;
      background-color: rgba(0, 0, 0, 0.5);
      box-shadow: 0 1px 2px #ccc, inset 0 1px 0 #fff;
    }
    
    /* 💩 Плохо */
    .selector, .selector-secondary, .selector[type=text] {
      padding:15px;
      margin:0px 0px 15px;
      background-color:rgba(0,0,0,.5);
      box-shadow:0px 1px 2px #CCCCCC,inset 0 1px 0 #FFFFFF}
    

    Порядок свойств

    Объявления логически связанных свойств группируются в следующем порядке:

    1. Позиционирование
    2. Блочная модель
    3. Типографика
    4. Оформление
    5. Анимация
    6. Разное

    Позиционирование следует первым потому, что оно влияет на положение блоков в потоке документа. Блочная модель идёт следующей, так как она определяет размеры и расположение блоков.

    Все остальные объявления, которые изменяют вид внутренних частей блоков и не оказывают влияния на другие блоки, идут в последнюю очередь.

    Сгруппированные объявления в правиле отделяются друг от друга пустой строкой.

    Порядок объявления подробных правил, таких как font-size, font-family, line-height, должен соответствовать порядку в сокращённой версии правила. В случае совместного использования подробных и сокращённых правил, первой должна идти сокращённая версия.

    .declaration-order {
      /* Позиционирование */
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      z-index: 100;
    
      /* Блочная модель */
      display: block;
      float: right;
      width: 100px;
      height: 100px;
      margin: 10px;
      padding: 10px;
    
      /* Типографика */
      font: normal 13px/1.5 "Arial", sans-serif;
      font-style: normal;
      font-size: 13px;
      line-height: 1.5;
      font-family: "Arial", sans-serif;
      text-align: center;
      color: #333333;
    
      /* Оформление */
      background-color: #f5f5f5;
      border: 1px solid #e5e5e5;
      border-radius: 3px;
      opacity: 1;
    
      /* Анимация */
      transition: color 1s;
    
      /* Разное */
      will-change: auto;
    }
    

    Имена классов

    • Имена классов пишутся строчными буквами, используется дефис (но не знаки нижнего подчёркивания или camelCase). Дефисы служат разделителями во взаимосвязанных классах (например, .button и .button-danger).
    • Имена классов должны быть такими, чтобы по ним можно было быстро понять какому элементу страницы задан класс: избегайте сокращений, не делайте их слишком длинными.
    • Для написания классов используются английские слова и термины. Транслитом названия классов и атрибутов не пишутся.
    /* 😊 Хорошо */
    .alert-danger { … }
    .tweet .user-picture { … }
    .button { … }
    .layout-center { … }
    
    /* 💩 Плохо */
    .testElement { … }
    .t { … }
    .big_red_button { … }
    .knopka { … }
    

    Варианты шрифта

    Альтернативные варианты шрифта и тип семейства указываются в конце перечисления font-family.

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

    Порядок шрифтов следующий:

    1. нестандартный шрифт
    2. веб-безопасный
    3. тип шрифта

    Список веб-безопасных шрифтов можно посмотреть здесь.

    /* 😊 Хорошо: указан альтернативный веб-безопасный шрифт и его тип семейства */
    body {
      font-family: "Helvetica", "Arial", sans-serif;
    }
    
    /* Кому-то нравится Arial, кому-то Tahoma */
    body {
      font-family: "Helvetica", "Tahoma", sans-serif;
    }
    
    /* 💩 Плохо: указан только нестандартный шрифт */
    body {
      font-family: "Helvetica";
    }
    
    /* 💩 Плохо: указан только нестандартный шрифт и тип семейства, альтернативный веб-безопасный шрифт отсутствует */
    body {
      font-family: "Helvetica", sans-serif;
    }
    
    /* 💩 Плохо: Georgia — шрифт с засечками, а нестандартный шрифт — без засечек */
    body {
      font-family: "Helvetica", "Georgia", sans-serif;
    }
    

    Использование некроссбраузерных решений

    Некоторые задачи могут быть легко решены CSS-свойствами, имеющими плохую поддержку браузерами. Использовать решения, приводящие к различному отображению в разных браузерах – допустимо редко.

    /* 😊 Хорошо: используется старый и проверенный хак */
    .aspect-ratio {
      padding-bottom: 56.25%;
    }
    
    /* 💩 Плохо: используется современное решение, которое плохо поддерживается */
    .aspect-ratio {
      aspect-ratio: 16 / 9;
    }
    

    Многосоставные селекторы

    Многосоставные (2-х и более) селекторы во многих случаях приводят к проблемам:

    • необходимость учитывать не только очерёдность, но и «вес» селектора
    • привязка стилей к определённой разметке (сложно модифицировать)

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

    /* 😊 Хорошо: используется селектор по одному классу */
    .btn {
      display: block;
    }
    
    /* 💩 Плохо: используется сложный селектор */
    .selector section div .btn {
      display: block;
    }
    

    Стилизация по тегам и по id

    Атрибут class специально существует для привязки стилей, используйте его. Редко допустима комбинация с тегами, псевдоселекторами или иными атрибутами. Не стилизуйте по id, ибо такие селекторы «больше весят» и их невозможно повторить в рамках одной страницы.

    /* 😊 Хорошо: используется класс */
    .btn {
      display: block;
    }
    
    /* 💩 Плохо: используется айди */
    #btn {
      display: block;
    }
    
    /* 💩 Плохо: используется тэг */
    .btn img {
      display: block;
    }
    

    Использование !important и/или overflow: hidden; для исправления багов

    Вместо поиска места проблемы (и её ликвидации) автор пишет правило с !important. Другой вариант: для ликвидации горизонтального скролла пишут overflow: hidden; на одной из общих обёрток.

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

    /* 💩 Плохо: горизонтальный скролл скрывается через костыль */
    body {
      overflow: hidden;
    }
    
    /* 💩 Плохо: правило перекрывается через !important */
    .btn {
      display: block !important;
      padding: 20px !important;
    }
    

    Игнорирование переполнения/недополнения контентом

    Переполнение и недополнение контентом/субблоками должно быть главным, о чём вы думаете, когда пишите стилизацию.

    Если где-то есть текст, его может стать много или совсем мало (при этом вёрстка не должна сломаться, должна вести себя логично). Познакомьтесь с «Электрокардиографической одиннадцатиклассницей, предпочитающей циклопентанпергидрофенантрен» и с «Ю Ли».

    Если в дизайне показан поток из 6 блоков (по 2 в ряд), нужно учесть что блоков может стать от нуля до 13 (не особо важно сколько именно, важно что много и что будет неполный последний ряд).

    Один из «рефлексов верстальщика»: зафиксировал блоку ширину или высоту — подумай о переполнении.

    /* 💩 Плохо: фиксированная высота для блока с текстом */
    p {
      height: 24px;
    }
    

    Объединение стилей обёрток и отдельных блоков

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

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

    Если не хочется писать лишних обёрток, можно попробовать миксовать (термин из БЭМ) класс обёртки с классом блока на одном теге, но в этом случае вы (или другой разработчик) сможете смешать правила.

    /* 💩 Плохо: на один блок повесили все стили */
    .base-sidebar {
      width: 300px;
      height: 100%;
      font-size: 10px;
      line-height: 14px;
      background-color: #0e9c58;
    }
    
    /* 😊 Хорошо: стили разграничиваются */
    .base-sidebar {
      width: 300px;
      height: 100%;
    }
    
    .base-sidebar--green {
      background-color: #0e9c58;
    }
    
    .base-sidebar--text-size-xs {
      font-size: 10px;
      line-height: 14px;
    }
    
    /* 😊 Хорошо: используется дополнительная обёртка */
    .base-sidebar {
      width: 300px;
      height: 100%;
    }
    
    .base-sidebar .inner-wrapper {
      font-size: 10px;
      line-height: 14px;
      background-color: #0e9c58;
    }
    

    Программирование на CSS-препроцессорах (особенно если не умеете программировать)

    Не программируйте на CSS-препроцессорах. Когда мы разбираемся в работе/багах применённых стилей, меньше всего нам хочется тратить время на разбор сложных структур, из которых эти стили скомпилировались.

    Да, с Sass/LESS/Stylus можно написать код, который будет коротким и его будет довольно сложно понять, но это не признак крутости. Совсем наоборот: сложнее = хуже (дольше разбираться как это работает). Нечто, более или менее похожее на программирование допустимо в CSS-препроцессорах в примесях (к примеру, в примесях-генераторах правил модульной сетки).

    /* 💩 Плохо: тяжело читать */
    @mixin calc-grid-column($index, $class, $type) {
      @if ($type == width) and ($index > 0) {
        .col-#{$class}-#{$index} {
          width: percentage(($index / $grid-columns));
        }
      }
      @if ($type == push) and ($index > 0) {
        .col-#{$class}-push-#{$index} {
          left: percentage(($index / $grid-columns));
        }
      }
      @if ($type == push) and ($index == 0) {
        .col-#{$class}-push-0 {
          left: auto;
        }
      }
      @if ($type == pull) and ($index > 0) {
        .col-#{$class}-pull-#{$index} {
          right: percentage(($index / $grid-columns));
        }
      }
      @if ($type == pull) and ($index == 0) {
        .col-#{$class}-pull-0 {
          right: auto;
        }
      }
      @if ($type == offset) {
        .col-#{$class}-offset-#{$index} {
          margin-left: percentage(($index / $grid-columns));
        }
      }
    }
    

    Быстрое чтение

    Оставляйте пустую строку перед селектором или группой селекторов.

    Работая с CSS-препроцессорами, оставляйте пустую строку перед любым вложенным селектором и @media.

    /* 😊 Хорошо: отступы между строчками */
    
    .promo {
      display: block;
    
      &__container {...}
    
      &__item {...}
    }
    
    /* 💩 Плохо: отступы не соблюдены */
    
    .promo {
      display: block;
      &__container {...}
      &__item {...}
    }
    

    Сокращённая запись

    Избегайте сокращённых объявлений. К примеру, если нужно задать только нижний внешний отступ, пишите margin-bottom: 10px; вместо margin: 0 0 10px.

    /* 😊 Хорошо: изменяются только нужные свойства */
    .element {
      margin-bottom: 10px;
      background-color: red;
      background-image: url("image.jpg");
      border-top-left-radius: 3px;
      border-top-right-radius: 3px;
    }
    
    /* 💩 Плохо: изменяются свойства, которые нам и не нужны. Труднее читать. */
    .element {
      margin: 0 0 10px;
      background: red;
      background: url("image.jpg");
      border-radius: 3px 3px 0 0;
    }
    

    Медиа-выражения

    Помещайте media queries настолько близко к соответствующим наборам правил, насколько это возможно. Не объединяйте их в отдельную таблицу стилей, не помещайте их в конце файла.

    /* 😊 Хорошо: медиа выражения рядом с селектором */
    .element {
      margin-bottom: 10px;
    
      @media (min-width: 768px) {
        margin-bottom: 14px;
      }
    }
    
    .block {
      background-color: #0e9c58;
    
      @media (min-width: 768px) {
        background-color: #00d171;
      }
    }
    
    /* 💩 Плохо: создаётся отдельная таблица стилей */
    .element {
      margin-bottom: 10px;
    }
    
    .block {
      background-color: #0e9c58;
    }
    
    @media (min-width: 768px) {
      .element {
        margin-bottom: 14px;
      }
    
      .block {
        background-color: #00d171;
      }
    }
    

    Интерактивные элементы

    При создании интерактивных элементов (элементов, с которыми пользователь может как-то взаимодействовать — что-то происходит по нажатию на этот элемент или наведению на него), нужно учитывать следующие состояния:

    • hover — состояние при наведении мышью на элемент;
    • focus — состояние при «наведении» на элемент с клавиатуры (табом). Фокус должен быть явно виден на странице, т.е. должно быть однозначно видно и понятно, какой элемент сейчас под фокусом. Наилучшим вариантом является стандартный outline. Не рекомендуется заменять его на смену цвета текста \ фона, так как такое изменение малозаметно. Допускается смена цвета outline на тот, который более вписывается в дизайн сайта;
    • disabled — обязательное состояние, если семантически такое состояние есть.

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

    Учитывайте область клика небольших элементов. Стоит добавлять таким элементам дополнительный padding, чтобы область элемента стала больше и в него было проще попасть.

    Если на элемент можно кликать – следует использовать семантический тэг <button>.

    Если элемент ведёт на другую страницу – следует использовать семантический тэг <a>.

    Ни в коем случае не используйте div, span и другие неинтерактивные элементы.

    /* 😊 Хорошо: все состояния описаны. Псевдоэлементом увеличена область клика. */
    button {
      position: relative;
      width: 24px;
      height: 24px;
      background-color: #00d171;
    }
    
    button:hover,
    button:focus {
      background-color: #1aaa66;
    }
    
    button:active {
      background-color: #0e9c58;
    }
    
    button:disabled {
      opacity: 0.4;
      cursor: not-allowed;
    }
    
    button::before {
      position: absolute;
      top: 50%;
      left: 50%;
      width: calc(100% + 40px);
      height: calc(100% + 40px);
      transform: translate(-50%, -50%);
      content: '';
    }
    
    /* 💩 Плохо: состояние не описаны. На кнопку трудно кликать.  */
    button {
      position: relative;
      width: 24px;
      height: 24px;
      background-color: #00d171;
    }
    
    /* 💩 Плохо: интерактивный элемент сделан через <div>  */
    div.button {
      position: relative;
      width: 24px;
      height: 24px;
      background-color: #00d171;
    }
    

    Анимации

    Не анимируйте свойства, который вызывают reflow (layout) элемента. То есть те свойства, которые влияют на размеры элемента или на положение соседних элементов. К таким свойствам можно отнести width и margin. Анимация таких свойств будет медленной и будет работать медленно на слабых устройствах, лучше обойтись без анимации или изменить принцип анимации, чтобы можно было обойтись без reflow.

    Не анимируйте свойства, которые вызывают repaint у больших блоков. Такая анимация хоть и гораздо быстрее, чем анимация свойств с reflow, но всё равно может быть достаточно медленной.

    Лучшие свойства для анимации — свойства, которые вызывают только compositing. Такая анимация будет наиболее производительной. Основная проблема, что такие свойства — только opacity и transform. Но через них можно сэмулировать анимацию большинства остальных свойств.

    /* 😊 Хорошо: размер эмулируется с помощью transform */
    button {
      width: 24px;
      height: 24px;
    }
    
    button:hover,
    button:focus {
      transform: scale(2);
    }
    
    /* 💩 Плохо: анимируется запрещённое свойство.  */
    button {
      width: 24px;
      height: 24px;
    }
    
    button:hover,
    button:focus {
      width: 48px;
      height: 48px;
    }
    

    Явный transition-property

    Для transition следует явно указывать анимируемое свойство для увеличения производительности.

    /* 😊 Хорошо: указано анимируемое свойство */
    button {
      opacity: 1;
      transition-property: opacity;
      transition-duration: 0.2s;
      transition-timing-function: ease;
    }
    
    button:hover,
    button:focus {
      opacity: 0.9;
    }
    
    /* 💩 Плохо: анимируются все свойства  */
    button {
      opacity: 1;
      transition-property: all;
      transition-duration: 0.2s;
      transition-timing-function: ease;
    }
    
    button:hover,
    button:focus {
      opacity: 0.9;
    }
    

    Амперсанд

    Используйте амперсанд только перед:

    • разделителем БЭМ-элемента,
    • разделителем БЭМ-модификатора,
    • псевдоэлементом или псевдоселектором.

    Никогда не используйте амперсанд в местах разделения словосочетаний имён блоков, элементов или модификаторов.

    .promo {
      /* 😊 Хорошо: амперсанд перед псевдоклассом */
      &:hover { ... }
    
      /* 😊 Хорошо: амперсанд перед разделителем элемента */
      &__item {
    
        /* 💩 Плохо: амперсанд в месте разделения словосочетания в названии элемента  */
        &-link { ... }
      }
    
      /* 💩 Плохо: амперсанд в месте разделения словосочетания в названии блока  */
      &-shover { ... }
    }