БЭМ и чего вы о нём не знаете

БЭМ и чего вы о нём не знаете

Николай Громов

go-go-go!

Что такое БЭМ

Это компонентый подход к разработке веб-приложения: разделение интерфейса на независимые блоки (и их элементы).

В разметке реализуется атрибутами class.

Существует как методология и как стек технологий.

      <article class="blog-post">
        <h2 class="blog-post__title">...</h2>
        <div class="blog-post__content">
          ...
        </div>
        <footer class="blog-post__footer">...</footer>
      </article>
       
      <article class="blog-post  blog-post--accent">
        <h2 class="blog-post__title">...</h2>
        <div class="blog-post__content">
          ...
        </div>
        <footer class="blog-post__footer">...</footer>
      </article>
    

Что получаем с БЭМ?

  1. Единый язык для всех участников проекта.

Вопросы

Проверяем понимание БЭМ.

  1. Какие части страницы — всегда Блоки?

Вопросы

  1. В «шапке» есть кнопка, ей нужен margin, как это сделать?

Диалекты

Диалекты: канонiчный вариант

      <!-- main-menu — Блок -->
      <ul class="main-menu">
        <!-- main-menu__item — Элемент -->
        <li class="main-menu__item">
        <!-- main-menu__link — Элемент -->
          <a href="/home" class="main-menu__link">Home</a>
        </li>
        <!-- main-menu__item_active — Модификатор -->
        <li class="main-menu__item  main-menu__item_active">
          <a href="/about" class="main-menu__link">About</a>
        </li>
      </ul>
    

Диалекты: no-namespace

      <!-- main-menu — Блок -->
      <ul class="main-menu">
        <!-- main-menu__item — Элемент -->
        <li class="main-menu__item">
        <!-- main-menu__link — Элемент -->
          <a href="/home" class="main-menu__link">Home</a>
        </li>
        <!-- _active — Модификатор -->
        <li class="main-menu__item  _active">
          <a href="/about" class="main-menu__link">About</a>
        </li>
      </ul>
    

Диалекты: two dashes

      <!-- main-menu — Блок -->
      <ul class="main-menu">
        <!-- main-menu__item — Элемент -->
        <li class="main-menu__item">
        <!-- main-menu__link — Элемент -->
          <a href="/home" class="main-menu__link">Home</a>
        </li>
        <!-- main-menu__item--active — Модификатор -->
        <li class="main-menu__item  main-menu__item--active">
          <a href="/about" class="main-menu__link">About</a>
        </li>
      </ul>
    

Диалекты: CamelCase

      <!-- MainMenu — Блок -->
      <ul class="MainMenu">
        <!-- MainMenu__Item — Элемент -->
        <li class="MainMenu__Item">
        <!-- MainMenu__Link — Элемент -->
          <a href="/home" class="MainMenu__Link">Home</a>
        </li>
        <!-- MainMenu__Item_active — Модификатор -->
        <li class="MainMenu__Item  MainMenu__Item_active">
          <a href="/about" class="MainMenu__Link">About</a>
        </li>
      </ul>
    

Диалекты: React

      <!-- MainMenu — Блок -->
      <ul class="MainMenu">
        <!-- MainMenu-Item — Элемент -->
        <li class="MainMenu-Item">
        <!-- MainMenu-Link — Элемент -->
          <a href="/home" class="MainMenu-Link">Home</a>
        </li>
        <!-- MainMenu-Item_active — Модификатор -->
        <li class="MainMenu-Item  MainMenu-Item_active">
          <a href="/about" class="MainMenu-Link">About</a>
        </li>
      </ul>
    

Модификации

Модификации БЭМ: префиксы

b- — блок

o- — объект, e- — элемент

c- — компонент или контрол

l- — layout (раскладка), p- — page

u- — утилита

t- — тема оформления

g- — глобальный модификатор

is-/has- — состояния

      <section class="promo">
        <h2 class="promo__title  title">Купите наши цинковые вёдра</h2>
        <ul class="promo__list  grid">
          <li class="product-card  grid__item">...</li>
        </ul>
      </section>
    
      <section class="c-promo">
        <h2 class="c-promo__title  c-title">Купите наши цинковые вёдра</h2>
        <ul class="c-promo__list  l-grid">
          <li class="c-product-card  l-grid__item">...</li>
        </ul>
      </section>
    
      <ul class="l-list">
        <li class="l-list__item">
          <div class="c-checkbox">
            <input class="c-checkbox__input" id="op_1" type="checkbox">
            <label class="c-checkbox__label" for="op_1">Apples</label>
          </div>
        </li>
      </ul>
    
      <div class="o-media  c-user  c-user--premium">
        <img class="o-media__img  c-user__photo  c-avatar" src="" alt="" />
        <p class="o-media__body  c-user__bio">...</p>
      </div>
    

Модификации БЭМ: суффиксы

-nojs — убираемый суффикс стилизации состояния без JS

@sm, @md, @lg — адаптивные суффиксы

@print — вспомогательные классы для сокрытия блоков при печати

       
      <div class="o-media@md  c-user  c-user--premium">
        <img class="o-media@md__img  c-user__photo  c-avatar" src="" alt="" />
        <p class="o-media@md__body  c-user__bio">...</p>
      </div>
       
    

Эти суффиксы принимают формат @<контрольная точка>, и сообщают нам этот класс в следующем размере.

Здесь мы имеем o-media@md, что означает, что медиа-объект будет в этой контрольной точке.

Оригинал

Ошибки и проблемы

БЭМ-ошибки и проблемы

Именования блока/элемента с описанием «как выглядит».

      <div class="promo">
        <h2 class="promo__gray-title">...</h2>
      </div>
      <button class="button-red">Buy me!</button>
      <span class="black-icon">...</span>
    

БЭМ-ошибки и проблемы

Элементы элементов.

      <section class="tariff">
        <header class="tariff__header">
          <h3 class="tariff__header__title">Tariff № 2</h3>
        </header>
        <div class="tariff__info">
          <p class="tariff__info__price">
            200 <span class="tariff__info__price__icon"></span>
          </p>
        </div>
      </section>
    

БЭМ-ошибки и проблемы

Использование элемента в отсутствие блока.

      <section class="promo">
        ...
        <div class="promo__item">
          ...
          <!-- Блок slider отсутствует на странице -->
          <div class="slider__item">...</div>
        </div>
      </section>
    

БЭМ-ошибки и проблемы

Попытка комбинации имён сущностей в имени вложенного блока.

      <section class="tariffs">
        ...
        <div class="tariffs__item">
          <h3 class="tariffs__item-header">Tariff № 2</h3>
          <p class="tariffs__item-header">...</p>
          <div class="tariffs-item"> <!-- tariff — было бы лучше -->
            <div class="tariffs-item__main-info">...</div>
          </div>
        </div>
      </section>
    

БЭМ-ошибки и проблемы

Автомиксование.

      <section class="promo  promo__info">
        <h2 class="promo__title">Promo</h2>
        <div class="promo__list">
          ...
        </div>
      </section>
    

БЭМ-ошибки и проблемы

Использование класса-модификатора в одиночестве.

      <section class="promo">
        ...
        <div class="promo__item">...</div>
        <div class="promo__item--large">...</div>
        <div class="promo__item">...</div>
      </section>
    

БЭМ-ошибки и проблемы

Смешение модификаторов.

      <section class="article">
        <h2 class="article__heading  article__heading_level_1_active">...</h2>
        ...
      </section>
    

БЭМ-ошибки и проблемы

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

      <section class="layout-profile">
        <h2 class="layout-profile__name-header  ft-typography  _h1">...</h2>
        ...
      </section>
    
      .ft-typography { position: relative; }
      .ft-typography._h1 { color: #232428; font-family: Effra, sans-serif; }
    

БЭМ-ошибки и проблемы

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

      <div class="table">
        <div class="table__head">
          <div class="table__head-title  table__head-title--version">Версия</div>
          <div class="table__head-title  table__head-title--date">Дата</div>
          <div class="table__head-title  table__head-title--author">Автор</div>
          <div class="table__head-title  table__head-title--descr">Примечание</div>
        </div>
        ...
      </div>
    

БЭМ-ошибки и проблемы

Классы-хелперы.

      <section class="promo">
        <h2 class="promo__title  text-muted">Promo</h2>
        <div class="text-right">
          ...
        </div>
      </section>
    

БЭМ-ошибки и проблемы

Стили блока, влиящие на его окружение.

      <button class="btn">Button</button>
    
      .btn {
        /* много стилей и... */
        margin-right: 20px;
      }
    

БЭМ-ошибки и проблемы

Стили блока, в рассчёте на конкретный тег.

      <h2 class="subtitle">Subtitle</h2>
    
      .subtitle {
        margin-top: 20px;
        font-size: 24px;
        line-height: 1.2
      }
    

БЭМ-ошибки и проблемы

Несовпадение имени файла и стилизуемого (в файле) блока.

      src/scss/components/common.blocks/the-sidebar/the-sidebar.scss
    
      .sidebar { ... }
    
      src/scss/pages/common.blocks/athletes/athletes.scss
    
      .p-athletes { ... }
    

Сложные случаи

Вывод текста из WYSIWYG.

      .promo {
       
        &__text {
         
          h2 { ... }
         
          p { ... }
        }
      }
    

Сложные случаи

Контекстная модификация.

      function cth(c) { document.documentElement.classList.add(c) }
      'ontouchstart' in window ? cth('touch') : cth('no-touch');
      if (typeof InstallTrigger!=='undefined') cth('firefox');
      if (/*@cc_on!@*/false||!!document.documentMode) cth('ie');
    
      .product-minicard {
       
        .ie & { ... }
      }
    

Сложные случаи

Комбинации с легаси.

      <div class="glavnayaStranitsa">
        <h1 class="zagolovok">Заголовок</h2>
        ...
        <!-- Оправданное использование префикса b- -->
        <article class="b-product-minicard">...</article>
      </div>
    

Сложные случаи

Место применения модификатора.

      <div class="preloader">
        <!-- preloader__container — единственный прямой потомок -->
        <div class="preloader__container  preloader__container--sm"> ... </div>
      </div>
    
      <div class="preloader  preloader--sm">
        <!-- preloader__container — единственный прямой потомок -->
        <div class="preloader__container"> ... </div>
      </div>
    

Критика БЭМ

Критика БЭМ: нечитабельный HTML

      <ul class="article-rewind  article-rewind_type_static  article-rewind_lang_ru">
        <li class="article-rewind__next">
          <div class="article-rewind__next-text">Читать далее</div>
          <a class="article-rewind__next-link" href="...">Основные понятия</a>
        </li>
      </ul>
    
      <ul class="article-rewind  type_static  lang_ru">
        <li class="next">
          <div class="text">Читать далее</div>
          <a class="link" href="...">Основные понятия</a>
        </li>
      </ul>
    

Критика БЭМ: запрет глобальных модификаторов

      <!-- Сохрана разметка от автора «критики» -->
      <section class="promo-section  promo-section_color_white">
        ...
      </section>
    

Критика БЭМ: «запрет» «семантики» в селекторе

      <h1 class="article__title">...</h1>
      <h2 class="article__title  article__title--level-2">...</h2>
      <h3 class="article__title  article__title--level-2">...</h3>
    
      @for $index from 1 through 6 {
        h#{$index}.heading {
          font-size: (42px / $index);
        }
      }
    

Автоматизация

Автоматизация: полный стек

      // desktop.bundles/hello/hello.bemjson.js
      ({
        block : 'page',
        title : 'hello',
        head : [
          { elem : 'css', url : 'hello.min.css' }
        ],
        mods : { theme : 'islands' },
        content : [
          { block : 'hello' }
        ]
      })
    
      // desktop.bundles/hello/hello.bemjson.js
      ({
        ...
        content : [
          {
            block : 'hello',
            content : [
              {
                elem : 'greeting',
                content : 'Hello %user%!'
              }
            ]
          }
        ]
      })
       
    
      // desktop.blocks/hello/hello.bemhtml.js
      block('hello')(
        tag()('article')
      );
    
      /* desktop.blocks/hello/hello.css */
      .hello {
        color: green;
        padding: 10%;
      }
    

Автоматизация: BEML

      <div block="animals">
        <div elem="item" mix="block:unicorn, mod: [large, female]">
          <div block="unicorn" elem="photo"></div>
          <div elem="item-name"></div>
        </div>
      </div>
    
      <div class="animals">
        <div class="animals__item  unicorn  unicorn_large  unicorn_female">
          <div class="unicorn__photo"></div>
          <div class="animals__item-name"></div>
        </div>
      </div>
    

Автоматизация: PostHTML-bem

      <div block="animal" mix="block:elephant elem:trunk">
        <div elem="nose" mods="size:long">Nose</div>
      </div>
    
      <div class="animal  elephant__trunk">
        <div class="animal__nose  animal__nose_size_long">Nose</div>
      </div>
    

Автоматизация: bemto.pug

      +b.block1
        +e.element1 Foo
        +b.block2
          +e.A(href="#bar").element Bar
        +e.element2 Baz
    
      <div class="block1">
        <div class="block1__element1">Foo</div>
        <div class="block2">
          <a class="block2__element" href="#bar">Bar</a>
        </div>
        <div class="block1__element2">Baz</div>
      </div>
    

Вопросы?

Николай Громов.

Бонус
скидка 10% на курс по вёрстке в EpicSkills по промо-коду GROMOV10