Форум

Методологія

Інструментарій

Платформа

Спільнота

Часті питання

Чому БЕМ?

Блоки та елементи

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.
  • БЕМ використовує збирачі: ENB або bem-tools.

Замість Custom Elements — абстракція над DOM-деревом

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

У чому різниця між БЕМ і Bootstrap?

У термінах БЕМ Bootstrap — це набір зверстаних блоків. БЕМ — не бібліотека елементів інтерфейсу, а методологія, що дозволяє:

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

Бібліотека блоків, зроблених на БЕМ — bem-components. Існують також і інші БЕМ-бібліотеки.

В якому випадку створювати блок, у якому — елемент?

  1. Если фрагмент кода может использоваться повторно и не зависит от реализации других компонентов страницы, необходимо создавать блок.
  2. Если фрагмент кода не может использоваться самостоятельно, без родительской сущности (блока), в большинстве случаев создается элемент.

Виняток становлять елементи, реалізація яких для спрощення розробки вимагає поділу на більш дрібні частини — подэлементы. БЕМ-методологія не рекомендує створювати елементи елементів. В подобном случае вместо элемента необходимо создавать служебный блок.

Чому у БЕМ не рекомендується створювати елементи елементів (block__elem1__elem2)?

Наявність елементів елементів обмежує можливість змінювати внутрішню структуру блоку: елементи можна поміняти місцями, видалити або додати без коригування існуючого коду.

У методології БЕМ вкладену структуру підтримують тільки блоки (block__elem). Ім'я блоку задає простір імен, що гарантує залежність елементів від блоку.

Блок може мати вкладену структуру елементів в DOM-дереві:

<div class="block">
    <div class="block__elem1">
        <div class="block__elem2">
            <div class="block__elem3"></div>
        </div>
    </div>
</div>

Однак ця ж структура блоку в методології БЕМ завжди буде представлена плоским списком елементів:

.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}

Це дозволяє змінювати DOM-структуру блоку без внесення виправлень в коді кожного окремого елемента:

<div class="block">
    <div class="block__elem1">
        <div class="block__elem2"></div>
    </div>
    <div class="block__elem3"></div>
</div>

Структура блоку змінюється, а правила для елементів і їх назви залишаються колишніми.

Навіщо писати ім'я блоку в іменах модифікаторів і елементів?

Ім'я блоку в іменах БЕМ-сутностей забезпечує:


Важливо! Методологія БЕМ допускає вибір зручної стратегії іменування, але вимагає дотримання консистентности в назвах. Так, например, все варианты верны: 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">.

Пошук в коді

Явні та унікальні імена полегшують пошук необхідної сутності в коді і файловій структурі.

Порівняємо результати глобального пошуку при налагодженні проекту. Знайдемо модифікатор 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>

Навіщо створювати окремі директорії і файли для кожного блоку і технології?

Файлова структура БЕМ-проекту поділяється на вкладені директорії і файли для зручності розробки і підтримки проекту.

Дотримуватися рекомендованої файлової структури проекту не обов'язково. Ви можете використовувати будь-яку альтернативну структуру проекту, відповідну принципам організації файлової структури БЕМ, наприклад:

Навіщо використовувати 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">
</div>

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

Використання імені блоку в назві модифікатора забезпечує більш високий пріоритет CSS-правил при перевизначенні блоку. Селектор .header .button завжди буде мати пріоритет вище, ніж .button_active.

Причини використання імені блоку імені модифікатора

Можна об'єднувати тег і клас в селекторі (наприклад, button.button)?

Поєднання тега і класу в селекторі підвищує специфічність CSS-правил. При додаванні модифікатора правила блоку не зможуть бути перевизначені, так як специфічність селектора блоку вище.

Розглянемо приклад:

 <button class="button">

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

Додамо модифікатор:

 <button class="button button_active">

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

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

Чому у БЕМ не використовують користувальницькі теги (custom tags) для блоків?

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

Користувальницькі теги можуть застосовуватися для створення селекторів до блокам, але є ряд обмежень:

  • Неможливо використовувати мікси.
  • Не будь блок можна виразити користувальницьким тегом. Наприклад, для всіх посилань необхідний тег <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, якщо ім'я модифікатора вже містить всю інформацію про блоці?

Якщо писати block_mod замість block block_mod, то всі базові CSS-властивості блоку необхідно буде визначити в модифікаторі block_mod. Модифікатори можуть змінюватися як в процесі роботи блоку (наприклад, як реакція на DOM-події блоку), так і за запитом з інших блоків. Таким чином, копіювати CSS-код, що реалізує базову функціональність блоку, доведеться у всі модифікатори блоку. Це призведе до дублювання коду.

Чому не можна вказувати назву CSS-властивості в імені модифікатора: .block__element_border-color_grey?

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

Методологія БЕМ рекомендує вибирати імена модифікаторів, спираючись на семантику, а не візуальне оформлення.

Якщо ви помітили помилку, або хочете доповнити статтю, ви завжди можете або написати нам про це на Гітхабі, або поправити статтю з допомогою prose.io.