Головокружительное погружение в БЭМ

«Что означают -- и __ в названиях ваших классов?» — один из самых часто задаваемых мне вопросов.

Ответом будет — спасибо БЭМ и Николасу Галлахеру


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

Важно отметить, что я использую систему именования основанную на БЭМ, но изменённую в соответствии с предложениями Николаса Галлахера. Система именования, освещаемая в текущем посте, это не оригинальный БЭМ, a улучшенная его версия, которая мне нравится больше. Тем не менее, в независимости от фактических изменений в обозначениях, улучшенная версия основана на тех же принципах БЭМ.

Система именования использует такой шаблон:

.block{}
.block__element{}
.block--modifier{}

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

.site-search{} /* Блок */
.site-search__field{} /* Элемент */
.site-search--full{} /* Модификатор */

Цель БЭМ — рассказать другим разработчикам как можно больше о том, что делает кусок кода, только по названиям классов в разметке. Читая HTML с небольшим количеством классов внутри, вы можете увидеть взаимодействия во всем коде и между его частями; что-то может быть компонентом, что-то дочерним элементом — элементом этого компонента, а что-то может быть измененной копией — модификатором компонента.

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

.person{}
.person__hand{}
.person--female{}
.person--female__hand{}
.person__hand--left{}

Верхний блок это человек (.person), имеющий элементы, к примеру руки (.hand). Человек может быть разным, например женского пола (.female), и эта вариация, в свою очередь имеет свои элементы. Ещё раз, тоже самое, но записанное в «обычном» CSS:

.person{}
.hand{}
.female{}
.female-hand{}
.left-hand{}

Все эти классы имеют смысл, но выглядят несколько разобщёнными. Рассмотрим .female; к чему относится класс female? Что насчёт .hand? Может быть это дверная ручка или письменная? Используя БЭМ мы предоставляем разработчикам не только более подробную, но и более точную информацию; мы устанавливаем связи между элементами за счет одного только именования классов. Очень круто.

Давайте рассмотрим пример формы поиска на сайте ещё раз:

<form class="site-search  full">
    <input type="text" class="field">
    <input type="Submit" value ="Search" class="button">
</form>

Это обычные классы, по ним много не скажешь. Да, мы вполне можем так работать, но с БЭМ мы получим:

<form class="site-search  site-search--full">
    <input type="text" class="site-search__field">
    <input type="Submit" value ="Search" class="site-search__button">
</form>

Теперь видно, что у нас есть блок названный .site-search, у которого есть вложенный элемент .site-search__field. Также наглядно видно, что существует модификации блока .site-search имеющая свой собственный класс .site-search--full.

Давайте рассмотрим ещё один пример…

Если вы знакомы с OOCSS, то не возникнет трудностей и с абстракцией медиа объекта.

Обретая форму БЭМ, медиа объект выглядит так:

.media{}
.media__img{}
.media__img--rev{}
.media__body{}

Используя такой способ записи стилей, мы уже знаем, что .media__img и .media__body находят внутри .media и то, что .media__img--rev это небольшая модификация .media__img. И это информация полученная только по названиям селекторов!

Другим плюсом является ясность взаимосвязей внутри разметки. Рассмотрим пример с медиа объектом ещё раз:

<div class="media">
    <img src="logo.png" alt="Логотип «Рога и копыта»" class="img-rev">
    <div class="body">
        <h3 class="alpha">Добро пожаловать в компанию «Рога и копыта»</h3>
        <p class="lede">«Рога и копыта» — молодая, динамично развивающаяся компания</p>
    </div>
</div>

Из этого кода, мы никогда не сможем понять как классы .media и .alpha относятся к друг другу. Да и относятся ли? А что насчёт классов .body, .lede или .img-rev и .media? Из этого HTML кода невозможно представить, что есть компонент сам по себе, а что есть дополнительные элементы и опции. Если мы изменим код в соответствии с нотацией БЭМ:

<div class="media">
    <img src="logo.png" alt="Логотип «Рога и копыта»" class="media__img--rev">
    <div class="media__body">
        <h3 class="alpha">Добро пожаловать в компанию «Рога и копыта»</h3>
        <p class="lede">«Рога и копыта» — молодая, динамично развивающаяся компания</p>
    </div>
</div>

Теперь мы сразу видим, что .media — блок, а .media__img--rev элемент блока .media, этот элемент также имеет модификатор; ясно видно, что .media__body — неизменённый элемент блока .media. Вся картина взаимосвязей успешно складывается по именам классов. Это невероятно удобно и полезно.

Безобразный код

Одним из часто встречающихся аргументов против использования БЭМ является то, что он — уродлив; осмелюсь сказать, что если вы отказываетесь от использования кода, опираясь на то как он выглядит - вы просто не улавливаете сути. Если код тяжело читать и поддерживать и для этого нет достаточных оснований, то стоит задуматься, а стоит ли его использовать, но если код просто «выглядит странно», но если для этого есть веская причина, то стоит все взвесить, прежде чем от него отказываться

Я согласен с тем, что БЭМ выглядит немного странно, но возможности, которые он дает намного перевешивают недостатки, связанные с его внешним видом.

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

БЭМ’ить или не БЭМ’ить?

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

Тем не менее, при использовании БЭМ, важно помнить, что нет нужды использовать его повсюду, например:

.caps{ text-transform:uppercase; }

Этот CSS никогда не поместить в БЭМ методологию, это просто одиночное правило.

Еще один пример пример:

.site-logo{}

Это наш логотип; он может быть преобразован так:

.header{}
.header__logo{}

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

Например:

<div class="content">
    <h1 class="content__headline">Можно предположить, что лемма проецирует…</h1>
</div>

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

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

.site-logo{}
.site-logo--xmas{}

Мы можем быстро создавать разные варианты, используя -- синтаксис модификатора.

Самое трудное в БЭМ — выбор, когда начать и когда закончить пространство очередного блока и вопрос о необходимости использования методологии в каждом конкретном случае. Это одни из тех случаев, когда понимание придёт само.

Подведем итоги

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

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