Как структурировать CSS? Разбираемся в синтаксисе БЭМ

alexei30/08/2024 - 09:14
Как структурировать CSS? Разбираемся в синтаксисе БЭМ

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

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

Соглашение об именовании следует такой модели:


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

  • .block - более высокий уровень абстракции или компонента.
  • .block__element - потомок .block, который помогает формировать компонент .block как единое целое.
  • .block--modifier - другое состояние или версия компонента .block.

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


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

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


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

Блок верхнего уровня - это "person" (человек), у которого есть элементы, например, "hand" (рука). A у человека также есть варианты, такие как "female" (женщина), и у этого варианта, в свою очередь, есть элементы. Вот то же самое, но написаное "обычным" CSS:


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

У всего этого безусловно есть смысл, но все как-то несвязно. Возьмем, к примеру, .female: Женщина что? A как насчет .hand. В английском языке у этого слова много значений: Рука человека? Стрелка часов? Сторона в карточной игре? Используя БЭМ, мы можем быть более описательными, но при этом и намного более точными. Мы привязываем конкретные ссылки к другим элементам нашего кода только с помощью именования. Мощный инструмент.

Возьмем предыдущий пример формы поиска .site-search с "обычным" именованием:


<form class="site-search full">
    <input type="text" class="field">
    <input type="Искать" value="Поиск" class="button">
</form>

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


<form class="site-search site-search--full">
    <input type="text" class="site-search__field">
    <input type="Искать" value="Поиск" class="site-search__button">
</form>

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

Давайте возьмем другой пример...

Если вы знакомы с OOCSS, то вы, без сомнения, знакомы с медиаобъектом. В нотациях БЭМ медиаобъект будет иметь такой вид:


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

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

Еще одним преимуществом нашего подхода является преодоление следующей ситуации. Опять возьмем медиаобъект:


<div class="media">
    <img src="logo.png" alt="Логотип ФуКорп" class="img-rev">
    <div class="body">
        <h3 class="alpha">Добро пожаловать в ФуКорп</h3>
        <p class="lede">ФуКорп лучшая. Серьезно!</p>
    </div>
</div>

Глядя на этот HTML код, мы не можем понять, как классы .media и .alpha связаны друг с другом? И связаны ли они вообще? А как насчет .body и .lede или .img-rev и .media? Из этого HTML кода (если только мы не очень хорошо знакомы с данным медиаобъектом) нам совершенно не понятно, из чего состоит этот компонент, и что там является необязательным. Теперь перепишем его с помощью БЭМ:


<div class="media">
    <img src="logo.png" alt="Логотип ФуКорп" class="media__img  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 без модификатора. Все это только из названия классов. Это очень полезно.

Фу, уродство!

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

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

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

БЭМ или не БЭМ? Вот в чем вопрос

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

Однако, когда вы используете БЭМ, важно помнить, что вам не нужно использовать его везде. Возьмем, к примеру, такой селектор:


.caps { text-transform: uppercase; }

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

А вот еще один пример кода, который не относится к БЭМ:


.site-logo {}

Здесь у нас просто логотип. Конечно, его можно оформить и при помощи БЭМ следующим образом:


.header {}
.header__logo {}

Но в этом нет необходимости. Хитрость БЭМ заключается в том, чтобы знать, когда что-то попадает в соответствующую категорию. Просто потому что, если что-то находится внутри блока, это не всегда означает, что это на самом деле элемент БЭМ. В случае с нашим логотипом сайта он находится в .header чисто случайно. С таким же успехом он может быть в боковой панели или нижнем колонтитуле. Область действия элемента может начинаться в любом контексте, поэтому вам нужно убедиться, что вы применяете БЭМ только в той мере, в какой это необходимо. Другой пример:


<div class="content">
    <h1 class="content__headline">Lorem ipsum dolor...</h1>
</div>

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

Тем не менее, потенциально все открыто для перехода на территорию БЭМ. Возвращаясь к примеру с .site-logo, представим, что мы хотим иметь праздничную версию логотипа для рождественского дизайна сайта. Мы могли бы определить это так:


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

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

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

Заключительное слово

Итак, вот такой он, БЭМ (или его разновидность), - очень полезное, мощное и простое соглашение об именовании, которое облегчает чтение и понимание вашего кода CSS, упрощает работу с ним, его масштабирование, делает его более надежным и строгим.

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