[Перевод] Соглашения по именованию CSS-сущностей и экономия времени

Я слышал, как многие разработчики говорят, что ненавидят CSS. Опыт подсказывает мне, что причина здесь в том, что они не уделяют достаточно времени для того, чтобы изучить CSS. Да, речь идёт о не самом дружелюбном «языке», но он успешно используется для стилизации веб-страниц уже более 20-ти лет. Это впечатляет, и с технологиями такого уровня распространённости приходится считаться. Однако, по мере роста объема стилей, задействованных в некоем проекте, проявляется один большой минус CSS: его очень сложно поддерживать. А плохо написанные стили быстро превращаются в кошмар.

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

35fc0287b9cafc31be7a1050576457cd.jpg


Вы уже бывали в подобной ситуации, правда?

Использование имён, состоящих из слов, разделённых дефисами


Если вы много пишете на JavaScript, это значит, что вы привыкли к именам переменных в верблюжьем стиле.

var redBox = document.getElementById('...')


С точки зрения JS тут всё нормально, но тот же подход к именованию сущностей не очень хорошо подходит для CSS.

Например, так делать не следует:

.redBox {
  border: 1px solid red;
}


Вместо этого лучше применить такую запись:

.red-box {
   border: 1px solid red;
}


Подобный подход к именам — обычное дело в CSS. Пожалуй, такие имена лучше читаются, и, кроме того, они согласуются с именами свойств CSS.

// Верно
.some-class {
   font-weight: 10em
}
// Неверно
.some-class {
   fontWeight: 10em
}


Соглашение по именованию БЭМ


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

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

  • Роль селектора.
  • Область использования селектора.
  • Взаимоотношения между сущностями.


Доводилось ли вам когда-нибудь видеть имена классов, записанные так:

.nav--secondary {
  ...
}
.nav__header {
  ...
}


Это — результаты применения соглашения по именованию БЭМ.

Основы БЭМ на простом примере


▍Что такое «Б»?


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

Взгляните на следующее изображение.

09c91f5db45ca4d67e86df133e049698.png


Это изображение человечка выиграло множество престижных наград

Ну, эта картинка никаких наград не выигрывала, но нам она очень пригодится. Итак, человечек (stick-man) представляет собой компонент, то есть — некий блок дизайна.

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

Следуя озвученному выше принципу, идеальным именем класса для такого компонента может стать stick-man.

Компонент следует стилизовать следующим образом:

.stick-man {
  
 }


Итак, тут использовано имя, части которого разделены дефисом. Это добавляет порядка в наш код.

232b87640eb8b9506b598e08f8950094.png


Человечек — это .stick-man в CSS

▍Что такое «Э»?


Буква «Э» в аббревиатуре «БЭМ» означает «элемент». Блоки дизайна редко представляют собой некие «монолитные сооружения».

Так, например, у нашего человечка (stick-man) есть голова (head), две замечательных руки (arms) и ноги (feet).

824e19de4a7477a2236e4237b688c737.png


Составные части человечка

Сущности head, feet, arms — это элементы, которые находятся внутри главного компонента (блока). Их можно рассматривать как дочерние компоненты, то есть, они являются потомками родительского компонента.

Используя соглашение об именовании БЭМ, имена классов элементов получают, добавляя к имени главного компонента два символа подчёркивания, за которыми следует имя элемента. Например, так:

.stick-man__head {
}
.stick-man__arms {
}
.stick-man__feet {
}


▍Что такое «М»?


Буква «М» в аббревиатуре «БЭМ» символизирует модификаторы. Что если нашего человечка можно модифицировать, и он может быть либо синим (blue), либо красным (red)?

a7da7a6ee17c6d0519e9dace0193ee22.png


Синий человечек и красный человечек

В веб-приложении это может быть чем-то вроде красной (red) или синей (blue) кнопки. Это — те самые модификаторы компонентов, о которых идёт речь.

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

.stick-man--blue {
}
.stick-man--red {
}


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

37f2f0eaf0a3b438daabe9a9e7d3a0b9.png


Варианты человечка с головой разного размера

В этот раз модифицируется лишь элемент основного блока. Помните о том, что элемент — это компонент, вложенный в основной компонент. Конструкция .stick-man представляет собой блок, а .stick-man__head — элемент.

Как видно из вышеприведённого примера, дефис можно использовать и так:

.stick-man__head--small {
}
.stick-man__head--big {
}


Обратите внимание на применение двух дефисов. Такая конструкция используется для обозначения модификатора.

Полагаю, теперь всё должно быть понятно. Это и есть основы БЭМ.

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

Зачем использовать соглашения по именованию?


«В информатике есть лишь две сложные задачи: инвалидация кэша и именование сущностей»
Фил Карлтон

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

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

CSS-имена и JavaScript


Поговорим об использовании CSS-имён в JavaScript. Тут нам поможет начинающий программист Джон. Сегодня — его первый рабочий день. Ему предложили заняться следующим HTML-кодом:


Джон прочитал эту статью и понял, что siteNavigation — не очень хорошее имя. Поэтому он взялся за дело и выполнил рефакторинг кода:


Хорошо получилось, правда? Но, к неожиданности Джона, проект, частью которого является доверенный ему код, перестал нормально работать. В чём же дело? Проблема заключается в том, что где-то в JavaScript-коде было использовано применяемое ранее имя класса — siteNavigation:

//код на JavaScript
const nav = document.querySelector('.siteNavigation')


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

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

▍Применение имён классов, начинающихся с js-


Один из способов борьбы с подобными ошибками заключается в использовании имён классов, сформированных по шаблону js-*. Такие имена указывают на то, что к рассматриваемому элементу DOM обращаются из JS. Например:


В результате в JavaScript-коде можно будет использовать такую конструкцию:

//код на JavaScript
const nav = document.querySelector('.js-site-navigation')


Программист, знакомый с таким соглашением по именованию и увидевший имя класса js-site-navigation, сразу понял бы, что это имя используется в JS-коде для работы с элементом DOM и не стал бы менять его без крайней нужды (и без внесения соответствующих исправления в программу на JavaScript).

▍Применение атрибута rel


Я этот подход не использую, но я видел тех, кто его применяет. Вам знакома такая конструкция?


Атрибут rel определяет отношения между ресурсом, на который сделана ссылка, и текущим документом. В предыдущем примере с Джоном сторонники этого подхода поступили бы так:


В JS с этим можно работать следующим образом:

const nav = document.querySelector("[rel='js-site-navigation']")


У меня есть сомнения по поводу этого подхода, но вы вполне можете встретить его в каком-нибудь проекте. Цель подобного использования атрибута rel заключается в том, чтобы указать на то, что элемент используется в JavaScript.

▍Об атрибутах data


Некоторые разработчики используют атрибуты data для организации работы с элементами DOM из JavaScript. Однако, это неправильно. Такие атрибуты используются для хранения данных. Вот пример правильного использования data-атрибутов из кода Твиттера.

8c908157d23c5e75870f55a1bd08bf15.png


Правильное использование атрибутов data

Итоги


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

Уважаемые читатели! Какие схемы именования сущностей вы используете при работе с CSS?

© Habrahabr.ru