Форум

Методология

Инструментарий

Платформа

Сообщество

Часто задаваемые вопросы

Почему БЭМ?

Блоки и элементы

JavaScript

CSS

Не нашли ответ? — Задайте вопрос команде на форуме

В чем отличие БЭМ от OOCSS, AMCSS, SMACSS, SUITCSS?

  1. БЭМ работает не только с CSS, но и с JavaScript.
  2. БЭМ больше схож с Web Components, чем с перечисленными решениями для CSS. (В чем разница между БЭМ и Web Components?)
  3. БЭМ предоставляет комплексное решение по созданию архитектуры проекта и помогает организовать процессы разработки. Подробнее читайте в разделе Применение методологии для решения задач веб-разработки.

Подробнее о методологии БЭМ.

Можно использовать БЭМ только на уровне CSS. Для этого достаточно просто следовать рекомендациям методологии.

В чем разница между БЭМ и Web Components?

Поддержка браузеров

Инкапсуляция

  • В Web Components реализована через Shadow DOM.
  • В БЭМ — с помощью элементов блока.

Работа шаблонов

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

  • Web Components использует императивный принцип — интерполяцию строк.

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

Вместо импорта HTML — сборка

  • Web Components использует импорт HTML (HTML Imports), который работает непосредственно в браузере. Для объединения HTML-файлов используется инструмент Vulcanize.
  • БЭМ использует сборщики:

Вместо Custom Elements — абстракция над DOM-деревом

  • В Web Components используются Custom Elements. Такой подход позволяет разместить на одном DOM-узле только один компонент.
  • В БЭМ существует понятие БЭМ-дерева. БЭМ использует миксы — размещение нескольких БЭМ-сущностей на одном DOM-узле.

В чем разница между БЭМ и Bootstrap?

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

  • создавать архитектуру проекта;
  • разрабатывать веб-приложения независимыми блоками;
  • упрощать поддержку проектов.

Библиотека блоков, сделанных на БЭМ — bem-components. Существуют также и другие БЭМ-библиотеки.

В каком случае создавать блок, в каком — элемент?

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

Почему в БЭМ не рекомендуется создавать элементы элементов (block__elem1__elem2)?

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

Подробнее читайте в разделе Быстрый старт.

Зачем писать имя блока в именах модификаторов и элементов?

Имя блока в именах модификаторов и элементов обеспечивает:

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

  • context, ctx или c;
  • attributes, attrs или as.

Необходимо выбрать один из них и использовать во всем проекте.

Пространство имен

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

Миксы

При использовании миксов необходимо явно указывать неймспейс для модификаторов, чтобы было ясно к какой из сущностей на данном DOM-узле относится модификатор. Если имя блока не указать, модификатор применится ко всем миксуемым БЭМ-сущностям.

Например, рассмотрим микс пункта меню (menu__item) и кнопки (button):

<div class="menu__item button"></div>

Добавим модификатор active в сокращенной форме записи (без имени блока):

<div class="menu__item button active"></div>

В таком виде HTML-разметка не дает понять, к чему относится модификатор: к пункту меню (menu__item.active) или к кнопке (button.active). Имя блока (button_active) явно указывает на БЭМ-сущность, к которой будет применен модификатор.

Также запись <div class="block mod"> не дает понять, какие БЭМ-сущности используются в работе. Например, из записи <div class="checkbox button"> нельзя однозначно определить, это микс модификатора и блока или микс двух блоков.

Полное имя модификатора <div class="block block_mod"> показывает, о каких сущностях идет речь:

<div class="checkbox checkbox_button"></div>

Поиск в коде

Явные и уникальные имена облегчают поиск необходимой сущности в коде и файловой структуре.

Сравним результаты глобального поиска при отладке проекта. Найдем модификатор active. В сокращенном виде (active) в результаты поиска попадут все возможные комбинации и HTML-фрагменты, где встречается active. В записи, рекомендуемой методологией, само название уже будет содержать уточняющий параметр в виде имени блока (button_active). Так как имя модификатора уникально, в результаты поиска попадут только нужные фрагменты кода.

Почему нельзя писать имя модификатора блока в имени элемента (block_mod__elem)?

Элемент — составная часть блока, а не модификатора блока. Таким образом, только имя блока может задавать пространство имен для элементов.

Это важно, потому что:

  • Блок может иметь много модификаторов.
<div class="block block_mod1 block_mod2 block_mod3">
    <div class="block__elem"></div>
</div>
  • Модификатор определяет состояние блока/элемента, которое может быть изменено во время выполнения скрипта JavaScript.

Как сделать глобальные модификаторы для блоков?

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

Если требуется вынести CSS-свойство за пределы одного блока и применять его к разным БЭМ-сущностям в проекте, необходимо создавать отдельный блок, реализованный в технологии CSS.

БЭМ позволяет совмещать реализацию разных блоков с помощью миксов:

<div class="block1 block2"></div>

Когда создавать булевый модификатор, а когда модификатор вида «ключ-значение»?

Полное имя модификатора создается по схеме:

  • Для булевых модификаторов — block-name_mod-name.
  • Для модификаторов вида «ключ-значение» — block-name_mod-name_mod-val.

Имя модификатора показывает, о каком состоянии идет речь. Если важно только наличие или отсутствие модификатора у блока, а его значение несущественно, следует использовать булевый модификатор. Например, модификатор, описывающий состояние «отключен»: disabled.

Пример

<div class="block block_disabled"></div>
<div class="block block_visible"></div>
<div class="block block_checked"></div>

Если состояний у блока может быть несколько, следует использовать модификатор вида «ключ-значение». Например, для описания размеров блока можно использовать модификатор size с допустимыми значениями s, m и l.

Пример

<div class="block block_size_s"></div>
<div class="block block_size_m"></div>
<div class="block block_size_l"></div>

Зачем создавать отдельные директории и файлы для каждого блока и технологии?

Файловая структура БЭМ-проекта разделяется на вложенные директории и файлы для удобства разработки и поддержки проекта.

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

Как правильно изменять внешний вид каждого экземпляра блока на странице?

Задача

Переиспользовать кнопку (блок button) из формы поиска (блок search-form) в блоке авторизации (auth). Кнопки должны отличаться по цвету и иметь разные отступы.

Решение

Рассмотрим пример DOM-дерева:

<form class="search-form">
    <input type="text" class="input">
    <button type="submit" class="button">Search</button>
</form>

<form class="auth">
    <input type="text" class="login">
    <input type="password" class="password">
    <!-- Здесь будет кнопка -->
</form>

Первое, что необходимо сделать — скопировать код кнопки в блок auth.

HTML

<form class="search-form">
    <input type="text" class="input">
    <button type="submit" class="button">Search</button>
</form>

<form class="auth">
    <input type="text" class="login">
    <input type="password" class="password">
    <button type="submit" class="button">Sign in</button>
</form>

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

Добавим кнопкам классы search-form__button, auth__button соответственно.

HTML

<form class="search-form">
    <input type="text" class="input">
    <button type="submit" class="search-form__button button">Search</button>
</form>

<form class="auth">
    <input type="text" class="login">
    <input type="password" class="password">
    <button type="submit" class="auth__button button">Sign in</button>
</form>

Теперь каждая кнопка имеет соответствующие только ей уникальные CSS-правила, определяющие отступы.

CSS

.search-form__button {
    margin: 30px;
}

.auth__button {
    margin: 40px;
}

Цветовое оформление блоков может быть реализовано с помощью:

  • модификатора — примеяется, если существует вероятность переиспользовать блок в данном цветовом оформлении;
  • микса — применяется, если блок имеет специфичное оформление только для данного окружения и в данном виде точно не будет переиспользован на проекте.

Добавим модификаторы: button_theme_lite, button_theme_dark.

HTML

<form class="search-form">
    <input type="text" class="input">
    <button type="submit" class="search-form__button button button_theme_lite">Search</button>
</form>

<form class="auth">
    <input type="text" class="login">
    <input type="password" class="password">
    <button type="submit" class="auth__button button button_theme_dark">Sign in</button>
</form>

Cоответственно, CSS-реализация будет иметь такой вид:

.button_theme_lite {
    background: #fff;
}

.button_theme_dark {
    background: #000;
}

Зачем использовать i-bem.js, если можно писать на jQuery?

i-bem.js это специализированный фреймворк для разработки проектов на JavaScript в терминах блоков, элементов и модификаторов.

i-bem.js не предназначен для замены фреймворка общего назначения, такого как jQuery.

i-bem.js позволяет:

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

Почему нежелательно использовать вложенные селекторы?

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

Методология БЭМ допускает использование таких селекторов, но рекомендует по максимуму его сократить.

Например, вложенность уместна, чтобы менять элементы в зависимости от состояния блока или заданной ему темы:

.nav_hovered .nav__link
{
    text-decoration: underline;
}
.nav_theme_islands .nav__item
{
    line-height: 1.5;
}

Почему в БЭМ не рекомендуется использовать комбинированные селекторы для создания CSS-правил к модификатору?

Комбинированные селекторы усложняют переопределение блока, так как имеют более высокую специфичность в CSS, чем одиночные. Специфичность комбинированного селектора для модификатора блока (.block1.mod) и для переопределенного блока (.block2 .block1) одинакова. Переопределение блока будет зависеть только от порядка объявления правил в декларации.

Рассмотрим пример:

<div class="header">
  <button class="button active">...</button>
</div>

Правила модификатора active для кнопки записываются как комбинированный селектор .button.active. При переопределении кнопки с помощью родительского блока header, создается селектор .header .button. Специфичность обоих селекторов одинакова, значит применение CSS-правил определяется порядком их объявления в декларации.

Использование имени блока в названии модификатора обеспечивает более высокий приоритет CSS-правилам при переопределении блока. Селектор .header .button всегда будет иметь приоритет выше, чем .button_active.

Причины использования имени блока в имени модификатора

Можно ли объединять тег и класс в селекторе? Например, button.button.

Совмещение тега и класса в селекторе повышает специфичность CSS-правил. При добавлении модификатора правила блока не смогут быть переопределены, так как специфичность селектора блока выше.

Рассмотрим пример:

<button class="button">...</button>

Записываем для него CSS-правила в селекторе button.button.

Добавим модификатор:

<button class="button button_active">...</button>

Cелектор .button_active не переопределит свойства блока, записанные как button.button, так как специфичность button.button выше. Для успешного переопределения селектор модификатора блока также должен быть скомбинирован с тегом button.button_active.

В результате развития проекта могут появится блоки с селекторами input.button, span.button и, например, a.button. В таком случае все модификаторы блока button и вложенные в него элементы потребуют четыре разные декларации для каждого случая.

Почему в БЭМ не используют пользовательские теги (custom tags) для блоков?

Блоки могут выражаться в HTML с помощью пользовательских тегов, к которым создаются CSS-правила. В таком случае классы можно будет использовать только для модификаторов: <button class="mod">...</button>.

Пользовательские теги могут применяться для создания селекторов к блокам, но есть ряд ограничений:

  • Невозможно использовать миксы.
  • Не любой блок можно выразить пользовательским тегом. Например, для всех ссылок необходим тег <a>, а для полей — <input>.

Почему нельзя делать общий сброс стилей (reset)?

Блок — независимый компонент. На него не должны влиять CSS-правила, созданные для всей страницы. Это нарушает независимость блоков и затрудняет их повторное использование.

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

Если сбросить стили все-таки необходимо, в БЭМ это делается в каждом блоке.

Рассмотрим пример. Если в проекте блоки меню и список выражены в HTML с помощью тега <ul>, значит каждый блок должен предоставлять сброс CSS для <ul>. Повторов в результирующем коде можно избежать с помощью CSS-оптимизатора.

Если в проекте не используется CSS-оптимизатор, который объединяет селекторы с одинаковым набором правил, можно применить CSS-препроцессор. Тогда для каждого нового блока можно делать сброс правил, миксуя чистый код. Например, в SASS это будет выглядеть так:

.menu {
    @include reset-list;
}

.menu__item {
    @include reset-list-item;
}
...
.list {
    @include reset-list;
}

.list__item {
    @include reset-list-item;
}

Такой способ следует использовать только при отсутствии оптимизатора.

Почему нельзя писать block_mod вместо block block_mod, если имя модификатора уже содержит всю информацию о блоке?

Если оставить только класс модификатора без указания класса самого блока/элемента, то все базовые CSS-свойства блока необходимо будет определить в селекторе block_mod.

Модификаторы могут изменяться как в процессе работы блока (например, как реакция на DOM-события блока), так и по запросу из других блоков. Таким образом, копировать базовые CSS-свойства блока, придется во все его модификаторы.

Совмещение нескольких модификаторов на одном и том же DOM-узле (например, <div class="block_theme_christmas block_size_big">) приведет к дублированию кода, реализующего базовую функциональность (логику и стили) блока.

Почему нельзя указывать название CSS-свойства в имени модификатора: .block__element_border-color_grey?

  • При изменении внешнего вида блока или элемента придется менять не только CSS-код, но и названия селекторов. Например, если цвет границы изменится с серого (grey) на красный (red), нужно будет изменить шаблоны и, вполне вероятно, JavaScript-код.
  • При добавлении других свойств (фона, отступов), имя перестанет соответствовать содержанию модификатора.

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

Как переопределить CSS-свойства БЭМ-сущности в контрольных точках (breakpoints)?

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

Изменить CSS-свойства БЭМ-сущности в runtime можно:

  • на уровне CSS (с помощью медиазапросов). Имя CSS-селектора должно быть достаточно общим, для того чтобы его можно было использовать более чем с одной целью. Например, block.

    CSS

    @media screen and (min-width: 0px) and (max-width: 767px) {
        .block {
              left: 0;
        }
    }
    
    @media only screen and (min-width: 768px) and (max-width: 1023px)  {
        .block {
            right: 0;
        }
    }
    
  • на уровне JavaScript (с помощью переключения модификатора). Имена CSS-селекторов должны быть максимально конкретными. Например, block_position_left, block_position_right.

    CSS

    .block_position_left {
        left: 0;
    }
    
    .block_position_right {
        right: 0;
    }
    

    Изменение CSS-классов на DOM-узле происходит при помощи JavaScript.

Если вы заметили ошибку или хотите чем-то дополнить статью, вы всегда можете или написать нам об этом на Гитхабе, или поправить статью с помощью prose.io.