CSS GuideLines, часть 3. Именование классов

Original author: Harry Roberts
  • Translation
  • Tutorial


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

  • Для чего используется класс;
  • Где класс может быть использован;
  • С какими другими классами связан этот класс.

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

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

Разделение дефисом


Все слова в названиях классов должны быть разделены дефисом:

.page-head {}

.sub-content {}

CamelCase и знак подчеркивания не используются для классов, следующий пример неправилен:

.pageHead {}

.sub_content {}


БЭМ-подобное именование


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

БЭМ, то есть Блок, Элемент, Модификатор, это методология, созданная разработчиками Яндекса. Несмотря на то, что БЭМ — это довольно крупная методология, в данный момент мы заинтересованы только в ее способе именования элементов. Причем, мое соглашение по именованию немного отличается от оригинального БЭМ'a: принципы одни и те же, но синтаксис разный.

БЭМ разделяет компоненты верстки на три группы:
  • Блок: главный корневой элемент.
  • Элемент: часть блока.
  • Модификатор: вариант или модификация блока.

Проведем аналогию:

.person {}
.person__head {}
.person--tall {}

В начале класса всегда ставится название блока, для обозначения элемента мы отделяем название блока от названия элемента двумя подчеркиваниями (__), а для обозначения модификатора используем два дефиса (--).

В примере выше мы можем видеть, что .person {} — это блок; у него нет предков. .person__head {} — это элемент, часть блока; наконец, .person--tall — это модификатор, разновидность блока .person {}.

Использование блоков

Блок должен быть логической, самостоятельной единицей. Продолжая наш пример с классом .person {}: мы не можем создать класс .room__person, потому что .room {} — это самостоятельная единица. В таком случае стоит разделять блоки:

.room {}

    .room__door {}

.room--kitchen {}


.person {}

    .person__head {}

Если нам потребуется обозначить человека внутри комнаты, было бы правильнее использовать такой селектор — .room .person, который позволяет не городить кашу из кучи разных непонятных элементов и блоков.

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

.page {}


.content {}


.sub-content {}


.footer {}

    .footer__copyright {}

Каждая часть кода представляет свой собственный блок. Неправильный пример использования:

.page {}

    .page__content {}

    .page__sub-content {}

    .page__footer {}

        .page__copyright {}

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

Множество слоев

Если бы мы добавили к нашему блоку .person {} еще один элемент, скажем, .person__eye, то нам не нужно было бы при именовании элемента делать шаг назад, добавляя названия предыдущих элементов, вплоть до корневого элемента. То есть, правильно будет писать .person__eye, а не .person__head__eye.

Добавляем модификации элементов

Вам может потребоваться добавлять вариации элементов, это может быть сделано несколькими способами, в зависимости от того, как и почему эти элементы должны быть изменены. Опять же, если человек имеет голубые глаза, то в CSS это может быть описано так:

.person__eye--blue {}

Однако, в реальных проектах все бывает несколько сложнее. Прощу прощения за такую аналогию, но давайте себе представим человека с красивым лицом. Сам по себе он не особо красив, поэтому лучшим решением будет добавить модификатор к элементу .person__face {}:

.person__face--handsome {}

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

.person--handsome .person__face {}

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

.person {}

    .person__face {

        .person--handsome & {}

    }

.person--handsome {}

Заметьте, что мы не добавляем новый элемент .person__face внутрь элемента .person--handsome; вместо этого мы используем родительский селектор Sass внутри уже существующего селектора .person__face. Это значит, что все правила, связанные с .person__face будут находиться в одном месте, и нам не придется разбрасывать их по всему файлу. Это хорошая практика при работе с вложенным кодом: храните все нужные стили внутри одного контекста (в нашем случае, внутри .person__face).

Именование в разметке


Как ранее было замечено, соглашение по именованию классов наиболее полезно при работе с разметкой. Взгляните на следующий кусок разметки, не следующий нашему соглашению:

<div class="box  profile  pro-user">

    <img class="avatar  image" />

    <p class="bio">...</p>

</div>

Как классы .box и .profile связаны друг с другом? Как классы .profile и .avatar связаны друг с другом? Связаны ли они вообще? Зависит ли класс .bio от класса .pro-user? Можно ли использовать класс .avatar вне этой разметки?

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

<div class="box  profile  profile--is-pro-user">

    <img class="avatar  profile__image" />

    <p class="profile__bio">...</p>

</div>

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

JavaScript-хуки



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

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

Как правило, разработчики используют отдельный класс для js, начинающийся с префикса «js-», например:

<input type="submit" class="btn  js-btn" value="Follow" />

Такая разметка позволяет использовать стили .btn в любом другом месте, при этом не затрагивая поведения .js-btn.

data-* атрибуты

Также довольно часто разработчиками используются data-* атрибуты в качестве js-хуков, но это неправильно. data-* атрибуты, согласно спецификации, предназначены для хранения данных, недоступных на странице. data-* атрибуты созданы для хранения данных, а не для для привязки к js.

В продолжение темы...


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

Материалы для дополнительного изучения




Предыдущая часть: CSS GuideLines, часть 2. Комментирование кода
Share post

Similar posts

Comments 14

    +3
    Кстати, вы не могли бы пояснить, почему слова в названиях классов CSS должны быть разделены дефисом? Я нахожу это крайне неудобным, так как в большинстве редакторов такое написание приводит к невозможности выделить название класса двойным кликом чтобы скопировать его или вызвать поиск. Приходится выделять как группу слов.
      0
      Прошу не забывать о том, что все данные советы и рекомендации субъективны, они основаны на личном опыте автора ресурса CSS GuideLines, и совсем не обязательно беспрекословно им следовать. Он лишь описывает то, что использует в своей работе, и что находит для себя полезным.
        +3
        Ок, но почему? Когда я для себя составлял стайлгайд по CSS, у меня под каждым правилом была причина, почему именно так.
          0
          Хм, ну конкретную причину он не указывает, видимо, ему просто так удобнее. Для себя Вы можете использовать другой способ, который удобнее Вам :)
        +2
        Настройте редактор — удалите дефис из списка разделителей слов.
          +1
          В других языках это разделитель, знак минус между переменными (amount-discount), хотя последний пример правильнее было бы написать с пробелами для выразительности.
        +2
        CamelCase и знак подчеркивания не используются для классов, следующий пример неправилен

        Расскажите кто-нибудь, а почему?
          0
          Отписал выше.
            +3
            Потому, что такая система: дефис соединяет слова, подчёркивание разделяет, кэмлкейс гораздо сложнее считывается и не позволяет быстро выделять части слова. Гарри (автор этого гайда) придумал систему и использует её. Вы, в свою очередь, можете взять её, а можете придумать свою. Главное, чтобы система была в принципе и была сквозной для всего вашего кода.
              0
              Ясно, спасибо.
            +3
            Насчет двойного бэмовского подчеркивания.
            При первом знакомстве мне это сильно не понравилось — громоздко, избыточно, некрасиво, неизящно… Но решил все-таки попробовать
            И через некоторое время понял — а действительно удобно! И даже эстетика после некоторого периода привыкания перестала смущать.
              +1
              Я тоже впервые познакомившись с синтаксисом именования классов в БЭМ ужаснулся. А сейчас использую, и вполне удобно, только рад, что в свое время наткнулся на эту методологию :)
                +1
                Я использую, но не совсем в оригинале. Немного модифицировал и упростил.
                  0
                  Да, я так же. Ибо использовать в оригинале — это уж слишком.

            Only users with full accounts can post comments. Log in, please.