Содержание

Как писать классы по БЭМ?

БЭМ расшифровывается как «Блок Элемент Модификатор». На самом деле, это целый стэк технологий, из которого мы воспользуемся только соглашением по именованию классов.
Почему БЭМ?

Подробнее можно почитать в разделах Быстрый старт и Часто задаваемые вопросы на сайте bem.info.

Ниже показаны примеры кода.

1.Простой пример: Блок + Элемент

Допустим, у вас есть блок с заголовком, текстом и кнопкой внутри, например, это всплывающее окно — попап. Разметка:

    <div>
      <h3>Заголовок</h3>
      <div>Текст</div>
      <button>Кнопка</button>
    </div>

Добавляем класс содержащий назначение элемента: .popup:

    <div class="popup">
      <h3>Заголовок</h3>
      <div>Текст</div>
      <button>Кнопка</button>
    </div>

Теперь попробуем добавить классы вложенным элементам:

    <div class="popup">
      <h3 class="title">Заголовок</h3>
      <div class="text">Текст</div>
      <button class="button">Кнопка</button>
    </div>

Классы удобные, но не уникальные. Если на странице будут ещё элементы с классами .title и .text, их стили могут затронуть элементы в попапе. Селектор типа .popup .title может в будущем создать проблемы со специфичностью. Можно придумать другие классы, но чем больше похожих по смыслу элементов, тем сложнее придумывать новые классы.

А теперь применим БЭМ-нотацию: каждому элементу внутри блока добавим префикс с классом родителя, например, для заголовка это будет popup__title:

    <div class="popup">
      <h3 class="popup__title">Заголовок</h3>
      <div class="popup__text">Текст</div>
      <button class="popup__button">Кнопка</button>
    </div>

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

2.Пример посложнее: Блок + Элемент + Модификатор

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

    <div class="message">
      <h3 class="message__title">Заголовок сообщения</h3>
      <div class="message__text">Текст сообщения</div>
    </div>

Логично использовать одну и ту же разметку, но с разными цветовыми темами. Именно здесь очень пригодятся модификаторы.

    <div class="message message--success">
      <h3 class="message__title">Заголовок сообщения</h3>
      <div class="message__text">Текст сообщения</div>
    </div>
 
    <div class="message message--error">
      <h3 class="message__title">Заголовок сообщения</h3>
      <div class="message__text">Текст сообщения</div>
    </div>

Обоим элементам можно добавить одинаковые стили используя общий класс .message и так же легко можно добавить отдельные стили для каждого из них, используя уникальный класс с модификатором:

    .message {
      border: 1px solid gray;
    }
      .message--success {
        border-color: green;
      }
 
      .message--error {
        border-color: red;
      }

Оба сообщения будут иметь рамку толщиной один пиксель, но для сообщения об успешной операции она будет зелёной, а для сообщения об ошибке — красной.

3.Ещё сложнее: что делать, если хочется сделать элемент элемента?

Например, на странице есть блок новостей:

    <div class="news">
        <h3>Новости</h3>
 
        <ul>
          <li><!-- новость --></li>
          <li><!-- новость --></li>
        </ul>
    </div>

Заголовок блока логично получает класс .news__title, список — .news__list, а отдельная новость — .news__item:

    <div class="news">
        <h3 class="news__title">Новости</h3>
 
        <ul class="news__list">
          <li class="news__item"><!-- новость --></li>
          <li class="news__item"><!-- новость --></li>
        </ul>
    </div>

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

    <div class="news">
        <h3 class="news__title">Новости</h3>
 
        <ul class="news__list">
          <li class="news__item">
            <h4>Заголовок новости</h4>
            <p>Текст новости</p>
          </li>
          <li class="news__item"><!-- новость --></li>
        </ul>
    </div>

Нам нужно добавить класс заголовку новости. Первым делом приходит в голову .news__title, но такой класс уже занят. Предположим, что второй элемент будет не .title, а .subject, тогда в CSS получается такое:

    .news__title { ... }
    .news__subject { ... }

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

Следующий вариант — .news__item__title, но в БЭМ нельзя создавать элемент элемента, и это понятно, потому что получается каша. Ещё вариант: .news__item-title — тоже не годится, потому что может быть неочевидным как title соотносится с item. Как же быть?

Решение простое: на уровне элемента .news__item можно объявить новый блок (например, .news-item), и строить вложенные классы уже от него. Да, это не самостоятельный переиспользуемый блок, здесь объявление блока нужно только для того, чтобы разгрузить селекторы. Что получается:

    <div class="news">
        <h3 class="news__title">Новости</h3>
 
        <ul class="news__list">
          <li class="news__item news-item">
            <h4 class="news-item__title">Заголовок новости</h4>
            <p class="news-item__text">Текст новости</p>
          </li>
          <li class="news__item"><!-- новость --></li>
        </ul>
    </div>

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

    .news__title { ... }
    .news-item__title { ... }

Простой и удобный выход из неудобной ситуации. Больше примеров разметки можно увидеть здесь. Ещё одно хорошее руководство по использованию БЭМ есть здесь.