Введение в методологию БЭМ
Опубликовано: 2022-03-11Что такое методология БЭМ?
Когда вы создаете небольшие веб-сайты, то, как вы организуете свои стили, обычно не представляет большой проблемы. Вы создаете свои обычные файлы, пишете весь необходимый CSS, и все. Однако, когда дело доходит до более крупных и сложных проектов, то, как вы организуете свой код, становится решающим . Структура кода еще более важна, если вы работаете в команде, состоящей из нескольких разработчиков внешнего и внутреннего интерфейса.
Сегодня существует множество методологий, направленных на сокращение кода CSS и упрощение сопровождения вашего кода CSS. В этой статье я объясню и приведу несколько примеров одного из них: БЭМ. BEM расшифровывается как Block Element Modifier . Основная идея заключается в том, чтобы ускорить процесс разработки и облегчить командную работу разработчиков, организовав классы CSS в независимые модули. Если вы когда-либо видели имя класса, такое как header__form--search
, то это БЭМ в действии. Да, классы можно называть очень долго, но все они читабельны и понятны.
Обратите внимание, что лучше всего использовать БЭМ только с классами, а не с идентификаторами, потому что классы позволяют при необходимости повторять имена и создавать более согласованную структуру кодирования. Кроме того, если вы хотите разбить свой сайт на организованные модули, он должен состоять из одной и той же структуры: блока, элемента и модификатора. Где каждый блок может иметь несколько элементов, и как блок, так и элементы могут иметь несколько модификаторов. Однако давайте сначала начнем с базовой структуры БЭМ и объясним ее на примерах.
Блокировать
Блок представляет объект на вашем сайте. Думайте об этом как о более крупных структурных фрагментах вашего кода. Наиболее распространенными блоками на каждом веб-сайте сегодня являются заголовок, контент, боковая панель, нижний колонтитул и поиск. Блоки в БЭМ всегда являются отправной точкой для привязки ваших классов CSS. Взгляните на несколько примеров блоков:
- содержание
- меню
- форма поиска
.content {/* Styles */} .menu {/* Styles */} .search {/* Styles */}
Элемент
Элемент — это компонент внутри блока, выполняющий определенную функцию. Это должно иметь смысл только в контексте его блока:
- содержательная статья
- пункт меню
- поле ввода поиска
.content__article {/* Styles */} .menu__item {/* Styles */} .search__input {/* Styles */}
Модификатор
Модификатор — это то, как мы представляем варианты блока. Если вы когда-либо использовали Bootstrap, то лучшим примером будут размеры кнопок. Размеры кнопок — это просто вариации размера самой кнопки, что делает ее модификатором:
- содержательная статья
- ссылка на меню
- поле поиска со значком или без него
.content__article--featured {/* Styles */} .menu__item--link {/* Styles */} .search__input--icon {/* Styles */}
Соглашения об именах
Основная цель методологии БЭМ — сделать имена CSS-селекторов максимально информативными и прозрачными. Оригинальный БЭМ-стиль определяется следующим образом:
Имя блока обычно состоит из одного слова, например .header
, но если у вас более длинное определение блока, оно разделяется одним дефисом -
:
.lang-switcher {/* Styles */}
Имя элемента начинается с двойного подчеркивания __
:
.lang-switcher__flag {/* Styles */}
Имя модификатора начинается с одиночного подчеркивания _
:
.lang-switcher__flag_basic {/* Styles */}
В методологии БЭМ есть только одно очень важное правило — модификатор нельзя использовать вне контекста его владельца.
Пример:
.btn_big {/* Styles */}
Вы можете использовать btn_big
, только если заголовок также определен.
Плохой пример:
<div class=”btn_big”>...</div>
Хороший пример:
<div class=”btn btn_big”>...</div>
Помимо этих оригинальных стилей БЭМ, существуют альтернативные схемы именования, такие как стили Harry Roberts и CamelCase.
Пример стиля Гарри Робертса:
.block-name__element-name--modifier-name {/* Styles */}
Пример стиля CamelCase:
.BlockName__ElementName_ModifierName {/* Styles */}
Других тоже немного, но эти два самые распространенные. Лично я являюсь поклонником соглашения об именах, предложенного Харрисом Робертсом, которое имеет следующие правила:
- Имена пишутся строчными буквами
- Слова в именах БЭМ-сущностей разделяются дефисом
-
- Имя элемента отделяется от имени блока двойным подчеркиванием
__
- Логические модификаторы разделяются двойным дефисом
--
- Модификаторы типа "ключ-значение" не используются.
Причина, по которой это соглашение об именах сформировано намного лучше, чем другие, заключается в том, что вы можете легко отличить элемент-модификатор от других. В исходных соглашениях об именах модификатор определялся бы так:
.block__element_modifier {/* Styles */}
Но, как видите, разницы между одинарным и двойным подчеркиванием не так уж и много. С другой стороны, двойной дефис обеспечивает четкое разделение, и модификатор сразу виден:
.block__element--modifier {/* Styles */}
Пример БЭМ в разных форматах
Обратите внимание, что помимо CSS, БЭМ также очень полезен для организации файлов JSON, XML, дерева или любого другого формата, поддерживающего вложенность. Думайте о методологии БЭМ как о хорошем способе создания пользовательского интерфейса.
Рассмотрим следующий HTML, структурированный в формате БЭМ:
<header class=”header”> <img class=”header__logo”> <form class=”header__search-from”> <input class=”header__search-from__input” type=”input”> <button class=”header__search-from__button” type=”button”> </form> <div class=”header__lang-switcher”></div> </header>
То же самое может быть достигнуто с использованием формата JSON и XML.
XML:
<block:header> <block:logo/> <block:search-from> <block:input/> <block:button/> </block> <block:lang-switcher/> </block>
JSON:
{ block: 'header', content: [ { block: 'logo' }, { block: 'search-form', content: [ { block: 'input' }, { block: 'button' } ] }, { block: 'lang-switcher' } ] }
Организация файловой системы БЭМ-проекта
В БЭМ очень важно правильно организовать ваши файлы. БЭМ не только обеспечивает отличную организацию классов CSS и делает их полностью понятными, но также дает очень удобную в сопровождении файловую структуру. Давайте возьмем пример проекта, используя технику организации файлов BEM с файлами SASS:
blocks/ input/ __box/ --big/ input__box--big.scss input__box.scss button/ --big/ button--big.scss
Как вы можете видеть выше, просто увидев структуру подпапок внутри вашей основной папки, все ясно и организовано. Таким образом, не имеет значения, кто работает после вас или работаете ли вы после кого-то, потому что невероятно легко следовать одному и тому же шаблону.
Разделение проекта БЭМ на платформы
Помимо простой организации ваших файлов с использованием методов методологии БЭМ, вы также можете заняться более конкретными вещами. Например, если вы создаете веб-проект, который будет полностью адаптивным, и клиент указал, что некоторые блоки на мобильных устройствах полностью отличаются от блоков на настольных устройствах, было бы лучше разделить структуру папок БЭМ на платформы. Пример организации кнопок на разных платформах:
common.blocks/ button/ button.scss desktop.blocks/ button/ buttons.scss mobile.blocks/ button/ button.scss
Обратите внимание, что это всего лишь пример, если вы хотите организовать весь свой проект с использованием методологии БЭМ. Файловое дерево со структурой БЭМ не обязательно для корректного использования БЭМ, вы можете использовать БЭМ только в некоторых сегментах проекта. До сих пор я не использовал эту строгую организацию файловой структуры БЭМ, где для каждого элемента и модификатора создается свой файл. Вместо этого я просто создаю файловую структуру для блоков, в которых есть объявление ее элементов и модификаторов.
БЭМ на практике
Поскольку теперь вы знакомы с соглашениями об именах, я продемонстрирую методологию БЭМ на практике. Допустим, у нас есть этот HTML-код в действии:
<a class=”btn btn--big btn--primary-color” href=”#” title=”Title”> <span class=”btn__price”>$3.99</span> <span class=”btn__text”>Product</span> </a>
Применяется следующая разметка CSS:
.btn__price {/* Styles */} .btn__text {/* Styles */} .btn--big {/* Styles */} .btn--primary-color {/* Styles */}
Не вводите в заблуждение. В наших примерах до сих пор у нас почти всегда были блок, элемент и модификатор, что не всегда обязательно.
Например, допустим, у нас есть блок с именем person . У человека есть ноги и руки, он также может быть женского или мужского пола. Если мы хотим определить человека мужского пола с правой рукой, это будет выглядеть так:
.person--male__hand--right {/* Styles */}
Теперь вы можете увидеть настоящий смысл БЭМ. Мы определили человека, модификатором которого является пол. Поскольку неважно, мужчина это или женщина, у него есть рука, а рука — это стихия. И опять же, у каждого человека может быть правая или левая рука, что опять же является модификатором.
В другом случае, если мы хотим определить общего человека одной рукой, мы сделаем это так:

.person__hand {/* Styles */}
Как вы можете заметить, как только вы освоитесь с БЭМ, с его помощью очень легко структурировать структуру CSS и HTML.
Использование БЭМ с препроцессорами CSS
Лично я не могу представить себе запуск любого нового проекта без использования одного из препроцессоров CSS. Как вы все знаете, препроцессоры — отличная вещь, они дают нам много преимуществ, а самое главное — идеально подходят для методологии БЭМ.
В следующем примере вы можете увидеть наиболее типичный пример БЭМ в сочетании с SASS:
.person { &__hand {/* Styles */} &__leg {/* Styles */} &--male { /* Styles */ &__hand { /* Styles */ &--left {/* Styles */} &--right {/* Styles */} } &__leg { /* Styles */ &--left {/* Styles */} &--right {/* Styles */} } } &--female { /* Styles */ &__hand { /* Styles */ &--left {/* Styles */} &--right {/* Styles */} } &__leg { /* Styles */ &--left {/* Styles */} &--right {/* Styles */} } } }
Код SASS будет скомпилирован в следующий CSS:
.person__hand {/* Styles */} .person__leg {/* Styles */} .person--male {/* Styles */} .person--male__hand {/* Styles */} .person--male__hand--left {/* Styles */} .person--male__hand--right {/* Styles */} .person--male__leg {/* Styles */} .person--male__leg--left {/* Styles */} .person--male__leg--right {/* Styles */} .person--female {/* Styles */} .person--female__hand {/* Styles */} .person--female__hand--left {/* Styles */} .person--female__hand--right {/* Styles */} .person--female__leg {/* Styles */} .person--female__leg--left {/* Styles */} .person--female__leg--right {/* Styles */}
Если вы хотите пойти еще дальше, вы можете использовать удобные миксины SASS для БЭМ:
/// Block Element /// @param {String} $element - Element's name @mixin element($element) { &__#{$element} { @content; } } /// Block Modifier /// @param {String} $modifier - Modifier's name @mixin modifier($modifier) { &--#{$modifier} { @content; } }
И вы можете использовать его следующим образом:
.person { @include element('hand') {/* Person hand */} @include element('leg') {/* Person leg */} @include modifier('male') { /* Person male */ @include element('hand') { /* Person male hand */ @include modifier('left') { /* Person male left hand */ } @include modifier('right') { /* Person male right hand */ } } } }
Что приведет к следующему выводу CSS:
.person__hand { /* Person hand */ } .person__leg { /* Person leg */ } .person--male { /* Person male */ } .person--male__hand { /* Person male hand */ } .person--male__hand--left { /* Person male left hand */ } .person--male__hand--right { /* Person male right hand */ }
Я знаю, что, скорее всего, у вас не будет варианта использования так долго, но это отличный пример того, как используется БЭМ и почему он такой мощный, как в небольших, так и в крупных проектах.
Запуск вашего БЭМ-проекта
Как объясняется в официальной документации BEM, самый простой способ начать свой собственный проект BEM — использовать существующий репозиторий GIT. Просто используйте команду Git clone:
$ git clone https://github.com/bem/project-stub.git
Затем перейдите во вновь созданный каталог и установите все зависимости:
$ npm install
Все необходимые зависимости будут установлены:
Соберите проект с помощью ENB:
$ node_modules/.bin/enb make
Запустите серверный режим для разработки:
$ node_modules/.bin/enb server
В результате появляется следующее сообщение:
Server started at 0.0.0.0:8080
Теперь это означает, что сервер запущен и работает. Теперь вы можете проверить результаты по этому адресу:
http://localhost:8080/desktop.bundles/index/index.html
Как видите, уже создано множество элементов, которые определены внутри файла bemjson
, который находится здесь:
project-stub/desktop.bundles/index/index.bemjson.js
Вы можете увидеть и изучить текущую структуру файла, который генерирует весь этот HTML, который вы видите в вашем файле index.html
на локальном хосте. Мы собираемся изменить этот файл, чтобы получить наш БЭМ-проект «Человек», о котором мы говорили в предыдущей главе. Вы можете удалить (или закомментировать) весь код из файла index.bemjson.js
и заменить его на этот:
module.exports = { block: 'page', title: 'Person BEM', favicon : '/favicon.ico', head : [ { elem : 'meta', attrs : { name : 'description', content : '' } }, { elem : 'meta', attrs : { name : 'viewport', content : 'width=device-width, initial-scale=1' } }, { elem : 'css', url : 'index.min.css' } ], scripts: [{ elem : 'js', url : 'index.min.js' }], content: [ { block: 'person', content: [ { elem: 'male', content: [ { elem: 'leg', mods: {side: 'left'}, content: 'Male person leg -- left' }, { elem: 'leg', mods: {side: 'right'}, content: 'Male person leg -- right' }, { elem: 'hand', mods: {side: 'left'}, content: 'Male person hand -- left' }, { elem: 'hand', mods: {side: 'right'}, content: 'Male person hand -- right' } ] }, { elem: 'female', content: [ { elem: 'leg', mods: {side: 'left'}, content: 'Female person leg -- left' }, { elem: 'leg', mods: {side: 'right'}, content: 'Female person leg -- right' }, { elem: 'hand', mods: {side: 'left'}, content: 'Female person hand -- left' }, { elem: 'hand', mods: {side: 'right'}, content: 'Female person hand -- right' } ] }, ] } ] };
Теперь будет сгенерирован следующий HTML:
<div class="person"> <div class="person__male"> <div class="person__leg person__leg_side_left"> Male person leg -- left </div> <div class="person__leg person__leg_side_right"> Male person leg -- right </div> <div class="person__hand person__hand_side_left"> Male person hand -- left </div> <div class="person__hand person__hand_side_right"> Male person hand -- right </div> </div> <div class="person__female"> <div class="person__leg person__leg_side_left"> Female person leg -- left </div> <div class="person__leg person__leg_side_right"> Female person leg -- right </div> <div class="person__hand person__hand_side_left"> Female person hand -- left </div> <div class="person__hand person__hand_side_right"> Female person hand -- right </div> </div> </div>
Как видно из приведенного выше кода, в этом сценарии использовалась схема кодирования БЭМ по умолчанию, поскольку мы просто используем настройки по умолчанию, которые нам предоставил БЭМ. Существует гораздо больше команд и опций, которые вы можете изучить и использовать, например, создание новых страниц, блоков или изменение BEM HTML. Я не буду углубляться в это, все это можно найти в официальной документации БЭМ.
Преимущества и проблемы
Преимущества
- БЭМ отлично подходит для поддержания. Сколько раз вам приходилось работать после кого-то над крупномасштабным проектом, и вы просто слишком боялись что-либо изменить, чтобы не рухнуло что-то неизвестное? При использовании БЭМ вы точно знаете назначение элемента и в каком блоке он может появиться.
- Имена классов логичны и интуитивно понятны, и каждый член команды знает, что этот элемент делает на веб-сайте. БЭМ дает каждому участнику проекта декларативный синтаксис, которым они могут поделиться, чтобы они были на одной странице.
- БЭМ устраняет вложенные селекторы CSS. Каждый элемент HTML имеет свой собственный класс CSS, и по его имени вы знаете, какова его цель. Один селектор, чтобы управлять ими всеми .
Опасения и распространенные ошибки
- Не заходите слишком глубоко во вложенность. Главное правило должно заключаться в том, чтобы не использовать более двух уровней родительского и дочернего элементов.
- Будьте осторожны с тем, где вы начинаете область действия блока. Распространенной ошибкой здесь является то, что разработчик использует блок, но не понимает, что на более позднем этапе разработки этот же блок будет иметь основной родительский блок, что может нарушить правило вложенности.
- Избегайте SASS @extend. Процитируем Гарри Робертса по этому поводу:
Вы можете создать большее количество комбинаций в представлении, не «связывая» классы вместе в Sass. HTML имеет гораздо лучший документальный след, так как вы можете увидеть каждый класс, работающий с частью DOM. Ваш CSS остается намного тоньше, поскольку вам не нужно создавать новые классы-заполнители (или классы манифеста, которые их объединяют) каждый раз, когда вы хотите создать новую часть пользовательского интерфейса.
Заключение
Когда я впервые увидел схему кодирования БЭМ, моей первой мыслью было:
Эти классы слишком длинные, чтобы писать и читать.
Но после того, как я попробовал, теперь я не могу представить себе запуск нового проекта без его использования. Для меня БЭМ значительно улучшил ремонтопригодность моего кода, и я могу с уверенностью сказать, что каждый разработчик, который собирается «броситься» в проект на основе БЭМ, очень быстро догонит всю структуру кода.
Несмотря на все это, в социальных сетях ведется много дискуссий о БЭМ. Некоторые говорят, что BEM не годится, задаваясь вопросом, почему они должны писать такие классы с длинными именами вместо того, чтобы просто использовать вложенные элементы HTML по умолчанию. Что ж, никто не говорит, что вам должен нравиться БЭМ, но факт в том, что большинство фронтенд-разработчиков принимают его и находят чрезвычайно полезным.