Введение
БЭМ (Блок, Элемент, Модификатор) - компонентный подход к веб-разработке. В его основе лежит принцип разделения интерфейса на независимые блоки. Он позволяет легко и быстро разрабатывать интерфейсы любой сложности и повторно использовать существующий код, избегая «Copy-Paste».
Блок
Функционально независимый компонент страницы, который может быть повторно использован. В HTML блоки представлены атрибутом class.
Особенности:
Пример:
<!-- Верно. Семантически осмысленный блок `error` --> <div class="error"></div> <!-- Неверно. Описывается внешний вид --> <div class="red-text"></div>
Таким образом обеспечивается независимость, при которой возможно повторное использование или перенос блоков с места на место.
- Принципы работы с блоками
<!-- Блок `header` -->
<header class="header">
<!-- Вложенный блок `logo` -->
<div class="logo"></div>
<!-- Вложенный блок `search-form` -->
<form class="search-form"></form>
</header>
Элемент
Составная часть блока, которая не может использоваться в отрыве от него.
Особенности:
Пример:
<!-- Блок `search-form` -->
<form class="search-form">
<!-- Элемент `input` блока `search-form` -->
<input class="search-form__input">
<!-- Элемент `button` блока `search-form` -->
<button class="search-form__button">Найти</button>
</form>
- Принципы работы с элементами
Вложенность
Пример:
<!--
Верно. Структура полного имени элементов соответствует схеме:
`имя-блока__имя-элемента`
-->
<form class="search-form">
<div class="search-form__content">
<input class="search-form__input">
<button class="search-form__button">Найти</button>
</div>
</form>
<!--
Неверно. Структура полного имени элементов не соответствует схеме:
`имя-блока__имя-элемента`
-->
<form class="search-form">
<div class="search-form__content">
<!--
Рекомендуется:
`search-form__input` или `search-form__content-input`
-->
<input class="search-form__content__input">
<!--
Рекомендуется:
`search-form__button` или `search-form__content-button`
-->
<button class="search-form__content__button">Найти</button>
</div>
</form>
Имя блока задает пространство имен, которое гарантирует зависимость элементов от блока (block__elem).
Принадлежность
Элемент - всегда часть блока и не должен использоваться отдельно от него.
Пример:
<!-- Верно. Элементы лежат внутри блока `search-form` -->
<!-- Блок `search-form` -->
<form class="search-form">
<!-- Элемент `input` блока `search-form` -->
<input class="search-form__input">
<!-- Элемент `button` блока `search-form` -->
<button class="search-form__button">Найти</button>
</form>
<!-- Неверно. Элементы лежат вне контекста блока `search-form` -->
<!-- Блок `search-form` -->
<form class="search-form">
</form>
<!-- Элемент `input` блока `search-form` -->
<input class="search-form__input">
<!-- Элемент `button` блока `search-form` -->
<button class="search-form__button">Найти</button>
Необязательность
Элемент - необязательный компонент блока. Не у всех блоков должны быть элементы.
Пример:
<!-- Блок `search-form` -->
<div class="search-form">
<!-- Блок `input` -->
<input class="input">
<!-- Блок `button` -->
<button class="button">Найти</button>
</div>
Когда создавать блок, когда - элемент?
- Создавайте блок
Если фрагмент кода может использоваться повторно и не зависит от реализации других компонентов страницы.
- Создавайте элемент
Если фрагмент кода не может использоваться самостоятельно, без родительской сущности (блока).
Исключение составляют элементы, реализация которых для упрощения разработки требует разделения на более мелкие части - подэлементы. В БЭМ-методологии нельзя создавать элементы элементов. В подобном случае вместо элемента необходимо создавать служебный блок.
Модификатор
Cущность, определяющая внешний вид, состояние или поведение блока либо элемента.
Особенности:
- Типы модификаторов
Булевый
Пример:
<!-- Блок `search-form` имеет булевый модификатор `focused` -->
<form class="search-form search-form_focused">
<input class="search-form__input">
<!-- Элемент `button` имеет булевый модификатор `disabled` -->
<button class="search-form__button search-form__button_disabled">Найти</button>
</form>
Ключ-значение
Пример:
<!-- Блок `search-form` имеет модификатор `theme` со значением `islands` -->
<form class="search-form search-form_theme_islands">
<input class="search-form__input">
<!-- Элемент `button` имеет модификатор `size` со значением `m` -->
<button class="search-form__button search-form__button_size_m">Найти</button>
</form>
<!--
Невозможно одновременно использовать два одинаковых модификатора
с разными значениями
-->
<form class="search-form
search-form_theme_islands
search-form_theme_lite">
<input class="search-form__input">
<button class="search-form__button
search-form__button_size_s
search-form__button_size_m">
Найти
</button>
</form>
- Принципы работы с модификаторами
С точки зрения БЭМ-методологии модификатор не может использоваться в отрыве от модифицируемого блока или элемента. Модификатор должен изменять вид, поведение или состояние сущности, а не заменять ее.
Пример:
<!-- Верно. Блок `search-form` имеет модификатор `theme` со значением `islands`-->
<form class="search-form search-form_theme_islands">
<input class="search-form__input">
<button class="search-form__button">Найти</button>
</form>
<!-- Неверно. Отсутствует модифицируемый класс `search-form` -->
<form class="search-form_theme_islands">
<input class="search-form__input">
<button class="search-form__button">Найти</button>
</form>
БЭМ-сущность
БЭМ-сущностями называются блоки, элементы и модификаторы.
Это понятие может применяться как частное, если рассматривается отдельная БЭМ-сущность, и как собирательное для блоков, элементов и модификаторов.
Микс
Способ использования разных БЭМ-сущностей на одном DOM-узле.
Миксы позволяют:
Рассмотрим пример микса блока и элемента другого блока.
Допустим, в проекте ссылки реализованы блоком link. Необходимо сделать ссылками пункты меню. Существует несколько способов:
БЭМ-дерево
Представление структуры веб-страницы в терминах блоков, элементов и модификаторов. Это абстракция над DOM-деревом, которая описывает имена БЭМ-сущностей, их состояния, порядок, вложенность и вспомогательные данные. В реальных проектах БЭМ-дерево можно выразить любым форматом, который поддерживает древовидную структуру.
Рассмотрим пример DOM-дерева:
<header class="header">
<img class="logo">
<form class="search-form">
<input class="input">
<button class="button"></button>
</form>
<ul class="lang-switcher">
<li class="lang-switcher__item">
<a class="lang-switcher__link" href="url">en</a>
</li>
<li class="lang-switcher__item">
<a class="lang-switcher__link" href="url">ru</a>
</li>
</ul>
</header>
Ему соответствует такое БЭМ-дерево:
header
logo
search-form
input
button
lang-switcher
lang-switcher__item
lang-switcher__link
lang-switcher__item
lang-switcher__link
Соглашение по именованию
Имя БЭМ-сущности уникально. Во всех технологиях (CSS, JavaScript, HTML) одна и та же БЭМ-сущность всегда называется одинаково. Основная идея соглашения по именованию - вложить смысл в имена и сделать их максимально информативными для разработчика.
Можно сравнить одно и тоже имя CSS-селектора, написанное разными способами:
Чтобы понять смысл первого имени, нужно вчитаться в каждое слово. В последних двух примерах имя явно разделяется на логические части. Но ни одно из имен пока не помогает точно определить, что menu - это блок, item - элемент, а visible - модификатор. Чтобы имена сущностей были однозначными и понятными, в БЭМ были разработаны правила формирования имен БЭМ-сущностей.
- Правила формирования имен
block-name__elem-name_mod-name_mod-val
Важно! В методологии БЭМ не существует элементов элементов. Правила именования запрещают создавать элементы элементов, но в DOM-дереве элементы можно вкладывать друг в друга.
Примеры:
- Имя блока
menu
HTML:
<div class="menu">...</div>
CSS:
.menu { color: red; }
- Имя элемента
menu__item
HTML:
<div class="menu">
...
<span class="menu__item"></span>
</div>
CSS:
.menu__item { color: red; }
- Имя модификатора блока
menu_hidden
menu_theme_islands
HTML:
<div class="menu menu_hidden">...</div>
<div class="menu menu_theme_islands">...</div>
CSS:
.menu_hidden { display: none; }
.menu_theme_islands { color: green; }
- Имя модификатора элемента
menu__item_visible
menu__item_type_radio
HTML:
<div class="menu">
...
<span class="menu__item menu__item_visible menu__item_type_radio">...</span>
</div>
CSS:
.menu__item_visible {}
.menu__item_type_radio { color: blue; }
Альтернативные схемы именования
- Стиль Two Dashes
block-name__elem-name--mod-name--mod-val
- Стиль CamelCase
blockName__elemName_modName_modVal
- Стиль React
BlockName-ElemName_modName_modVal