Вёрстка по БЭМ

Вёрстка, да и просто сам CSS, являются отдельным пунктом нелюбви разработчиков к фронтенду. Поддержка CSS в больших проектах может превратиться в хождение по минному полю, даже если применяются современные библиотеки/фреймворки, поддерживающие компонентный подход.

Если же вы будете придерживаться методологий вёрстки, то сможете облегчить поддержку большого проекта и локализовать изменения при решении задач.

Существует несколько различных CSS-методологий: 1. “Как быстрее” — да, это тоже методология; 2. SMACSS; 3. OOCSS; 4. FUN; 5. Atomic CSS; 6. БЭМ, про который мы и будем сейчас рассказывать.

Что же такое БЭМ?

БЭМ — это сокращение от «Блок-Элемент-Модификатор». В рамках данной методологии компоненты и части страниц логически разбиваются на блоки и элементы, а их CSS-классы пишутся специальным образом, например:

    <div class="company-logo__owl company__logo--new-year"></div>

или

    <div class="company-logo__owl company__logo_new-year"></div>

Сразу скажем, что правила именования могут отличаться от проекта к проекту. Как и некоторые другие вольности. Поэтому мы разберём только основы БЭМ и наиболее частые ошибки, возникающие при знакомстве с БЭМ.

Блок

Блок — это отдельный функциональный элемент, который может использоваться повторно.

Главная страница (home-page) — хороший пример блока, хоть он и не будет использоваться повторно.

Кнопка (button) — замечательный пример блока. То, что это блок, можно легко сказать по тому, что он будет присутствовать в самых разных местах.

В терминах React, Angular и Vue каждый блок будет реализовываться соответствующим компонентом.

Итак, предположим, что наш блок — это «логотип компании» (company-logo). В HTML он будет иметь следующую разметку:

    <div class="company-logo">
      OTUS
    </div>

Блок не должен зависеть от того, где он находится, поэтому в CSS не должно быть, например, margin. Приведём пример CSS:

    .company-logo {
      padding: 10px;
      background-color: rgba(0, 0, 0, 0.1);
    }

Элемент

Элемент — часть блока. У блока может быть несколько элементов, а может и не быть совсем. Допустим, у нашего блока есть два элемента — совёнок (owl) и текст логотипа (text).

Итак, наш блок с элементами будет иметь следующий вид. Обратите внимание на имена классов:

    <div class="company-logo">
      <div class="company-logo__owl"></div>
      <div class="company-logo__text">OTUS</div>
    </div>

Обратите внимание на разделитель в имени класса — два подчёркивания __. Он как раз и отделяет имена блоков и элементов.

Элемент обязательно должен находиться внутри блока, но элементы могут находиться «друг в друге» в разметке в рамках одного блока.

Итак, пример неправильного БЭМ:

    <!-- Неправильно! Элемент вне блока -->
    <div class="logo__container">
      <div class="logo">
        ...
      </div
    </div>

Элементы могут быть только у блоков. Приведём пример частой ошибки при использовании БЭМ:

    <!-- Неправильно! Элемент у элемента -->
    <div class="company-logo">
      <div class="company-logo__owl"></div>
      <div class="company-logo__text">
        <span class="company-logo__text__first-letter">O</span>TUS
      </div>
    </div>

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

    <div class="company-logo">
      <div class="company-logo__owl"></div>
      <div class="company-logo__text">
        <!-- элементы могут вкладываться друг-в-друга в разметке -->
        <span class="company-logo__first-letter">O</span>TUS
      </div>
    </div>

И приведём CSS:

    .company-logo {
      padding: 10px;
      background-color: rgba(0, 0, 0, 0.1);
    }

    .company-logo__owl {
      width: 30px;
      height: 40px;
      background-image: url(img/owl.png);
    }

    .company-logo__text {
      font-size: 20px;
      line-height: 40px;
    }

С первого взгляда, выглядит «не очень поддерживаемо». Со второго взгляда — можно код сократить, используя препроцессоры. На LESS эта простыня будет выглядеть куда приятнее:

    .company-logo {
      padding: 10px;
      background-color: rgba(0, 0, 0, 0.1);

      &__owl {       // обратите внимание, что нет повторения имени блока
        width: 30px;
        height: 40px;
        background-image: url(img/owl.png);
      }

      &__text {
        font-size: 20px;
        line-height: 40px;
      } 
    }

На самом деле, код на LESS не превратится в код CSS выше, а будет даже чуть-чуть правильнее кода CSS, который написан выше. Предлагаем читателям самостоятельно понять почему.

Модификатор

Предположим, что скоро Новый год, и нам необходимо нашего совёнка одеть в новогоднюю шапочку. И при этом нам не хочется менять уже написанный код (собственно, мы и хотим поддерживаемости). Для этого и существуют модификаторы:

    <div class="company-logo">
      <!-- мы потом классы чуть-чуть исправим -->
      <div class="company-logo__owl company__logo--new-year"></div>
      <div class="company-logo__text">OTUS</div>
    </div>

CSS код будет выглядеть следующим образом:

    .company-logo {
      padding: 10px;
      background-color: rgba(0, 0, 0, 0.1);

      &__owl {
        width: 30px;
        height: 40px;
        background-image: url(img/owl.png);

        &--new-year {
          background-image: url(img/owl-new-year.png);
        }
      }

      &__text {
        font-size: 20px;
        line-height: 40px;
      } 
    }

Обратите внимание, что в новом классе мы модифицировали только те свойства, которые необходимо. Это достигается за счёт того, что в тэге написаны классы company-logo__owl company__logo--new-year — исходные свойства применяются, потому что они есть в company-logo__owl, а перегруженные — потому что класс модификатора написан после.

В действительности, писать модификаторы непосредственно у элементов — не самая лучшая практика. Best practice состоит в том, чтобы писать модификаторы именно у блоков:

    <div class="company-logo company-logo--new-year">
      <!-- мы потом классы чуть-чуть исправим -->
      <div class="company-logo__owl"></div>
      <div class="company-logo__text">OTUS</div>
    </div>

Миксин (микс, миксина, примесь)

Про это часто забывают, но в действительности БЭМ — это БЭММ — «Блок-Элемент-Модификатор-Миксин». Блок часто является элементом другого блока, плюс отображение может отличаться от того места, где он находится (точнее — от того блока, где блок является элементом).

Итак:

    <header class="header">
      <!-- header__logo - это как раз и есть миксим к company-logo -->
      <div class="company-logo company-logo--new-year header__logo">
        <div class="company-logo__owl"></div>
        <div class="company-logo__text">OTUS</div>
      </div>
      <div class="header__menu">...</div>
    </div>

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

Приведём пример CSS:

    .header {
      &__logo {             // .header__logo  микс
        background: white;  // применится это правило
      }
    }

    .company-logo {
      padding: 10px;
      background-color: rgba(0, 0, 0, 0.1);
      // ...
    }

Если же мы напишем классы в другом порядке, то не сможем поменять цвет фона без !important:

    <div class="header__logo company-logo company-logo--new-year">

Учитывайте это, когда будете разрабатывать React/Angular/Vue компоненты.

Вот мы и рассмотрели основы и некоторые ошибки. Если вас заинтересовал БЭМ, то настоятельно рекомендуем погрузиться в мир БЭМ здесь: http://getbem.com/ https://ru.bem.info/

И не забывайте оставлять комментарии!