BEM CSS

#EPAMCDP, April 2016

Ihor Zenich, EPAM

BEM CSS

В исходниках этой презентации спрятались подсказки!

В комментах html написаны тезисы доклада и комментарии к слайдам требующим пояснений.

Презентация: delka.github.io/talks/2015/frontendweekend-bem/

Ihor Zenich

EPAM logo

Презентация: bit.ly/bem-css-guide

Зачем?

ещё один доклад про БЭМ…

БЭМ — семантичный!

Что он несёт?!

Pepelsbey

Имена БЭМ-классов создают дополнительный уровень логики

Есть DOM-дерево, а есть БЭМ-дерево.

<input class="big_red_button">
<input class="big_red_button order-button">
<input class="order-button discount-checkout__submit">
        

О чём будем говорить?

  1. Как вручную сверстать «по-БЭМ»
  2. Как не писать классы типа device-template-generic-indicator-control-slider-bar-d :)

Кстати, а зачем нужен БЭM?

Код, который тяжело поддерживать

Что в этом коде относится к классу user ?

<div class="media user premium">
  <img class="img photo avatar" src="" />
  <p class="body bio">...</p>
</div>
    

… и код, который ЛЕГКО поддерживать

Если мы перепишем этот код на BEM CSS, то все будет понятно просто из имён классов!

<div class="media user--premium">
  <img class="media__img user__photo avatar" src="" />
  <p class="media__body user__bio">...</p>
</div>
    

BEM CSS *

* CSS подмножество БЭМ

Full stack BEM

bemjson, bemhtml, bem-tools, enb, вот это вот всё…

Full stack BEM?

Когда он будет вам нужен — вы это сами поймёте.
Это будет момент, когда вам надоест писать html руками и вы захотите его генерировать.

Что значит «по-БЭМ»?

— Мы используем БЭМ, но не FullStack, а #b_ в CSS.
— Нет, не как в Яндексе.
— Как?
— Ну как Гарри Робертс писал…
— Как именно, он разное писал?
— Fuck.

Each time we have to understand what exactly BEM we are talking about. Both with customer and internally in the team.

2007 год

Виталий
Харисов

Виталий Харисов
Ya.ru

Пример верстки по БЭМ

Изначальная вёрстка →

Похоже на БЭМ, да?

Давайте приглядимся

Это был пример неправильного BEM CSS

Повышение специфичности

:(

bit.ly/not-bem

Непонятость БЭМ

Даже разработчики Google Material Design не смогли с первого раза правильно написать имена классов по БЭМ :)

Методология не менялась

.block

Независимый блок

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

БЭМ.Форум, Независимый блок

Обновленное определение блока

Логически и функционально независимый компонент страницы, аналог компонента в Web Components. Блок инкапсулирует в себе поведение (JavaScript), шаблоны, стили (CSS) и другие технологии реализации. Независимость блоков обеспечивает возможность их повторного использования, а также удобство в разработке и поддержке проекта.

bem.info, Методология

Правила независимости блока

  1. для описания элемента используется class, но не id
  2. каждый блок имеет префикс
  3. в таблице стилей нет классов вне блоков
БЭМ.Форум, История создания БЭМ (часть первая)

Как его таким написать?

Просто писать стили тупо на каждый блок.

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

А с препроцессорами БЭМ позволяет писать еще и очень чистый и логичный код.

Как проверить?

Просто навести на блок в инспекторе кода.
У него не должно быть каскада.

На самом деле каскад допускается, но его следует избегать.

.block__element

Элемент

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

bem.info, Методология

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

DOM-дерево

<ul>
  <li>
    <a>
      <span></span>
    </a>
  </li>
</ul>
    

DOM-дерево

.ul {}
.ul > li {}
.ul > li > a {}
.ul > li > a > span {}
    

DOM-дерево

<UL>
  <LI>
    <A>
      <SPAN></SPAN>
    </A>
  </LI>
</UL>
        

БЭМ-дерево

<ul class="menu">
  <li class="menu__item">
    <a class="menu__link">
      <span class="menu__text"></span>
    </a>
  </li>
</ul>
    

БЭМ-дерево

.menu {}
.menu__item {}
.menu__link {}
.menu__text {}
    

БЭМ-дерево

  <UL class="menu">
    <LI class="menu__item">
      <A class="menu__link">
        <SPAN class="menu__text"></SPAN>
      </A>
    </LI>
  </UL>
        

БЭМ дерево — чистая логика

БЭМ-дерево не зависит ни от чего, даже от размещения в документе.

БЭМ-дерево не привязано к визуальному представлению блоков, оно отображает только логику, это и есть новый уровень семантики!

.block__el__el__el

Так #b_ поняли и используют зарубежом

Да и не только зарубежом, чё уж греха таить…

Я тоже раньше так писал

      .form-buy-results__to-city__slider__tab__column_buy
    

Так делать нельзя

Как надо?

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

А в CSS

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

Элемент у элемента?

Если вам нужно сделать элемент у элемента, значит вам нужно:

Есть 2 варианта как это переписать

<div class="block">
    <div class="block__elem1">
        <div class="block__elem1__elem2"></div>
    </div>
</div>
    

1. Бить на блоки!

Делать новый блок

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

CSS будет линейным:

.block1 {}
.block1__elem1 {}
.block2 {}
.block2__elem1 {}
    

2. Рубить ветки!

Делать БЭМ-дерево с одноуровневой вложенностью элементов

<div class="block1">
    <div class="block1__elem1">
        <div class="block1__elem2"></div>
    </div>
</div>
    

CSS по-прежнему будет линейным:

.block1 {}
.block1__elem1 {}
.block1__elem2 {}
    

Типичная ошибка

Попытка вложить имя элемента в имя блока

Чтоб «схитрить» и «как-будто не вложить», написать не .block__el1__el2 а .blockel1__el2 или .block__el1el2. Так нельзя.

.block {}
.blockel1 {}
.blockel1__el2 {}
    

Будут проблемы при переносе

Будут проблемы при переносе

Попытались перенести «странный элемент» в другое место - получили элемент что завис «в воздухе» без блока-родителя

<div class='someblock'>
    <div class='blockel1__el2'></div>
</div>
    

Так можно делать только если .blockelem сохранит логический смысл при переносе в другой блок.

element > element нельзя в CSS, но можно в HTML!

Обратите внимание - вы не можете вкладывать элементы в элементы в CSS, но можете и должны вкладывать элементы в элементы в HTML! DOM-дерево и БЭМ-дерево могут быть разными.

Запрет есть исключительно про нейминг!

БЭМ-дерево на то и дерево, что поддерживает вложенность, поэтому в БЭМ-дереве, разумеется, разрешается вкладывать элементы в элементы, блоки в блоки, блоки в элементы.

Vladimir Grinenko, @tadatuta

Хватит!
Мы не за теорией сюда пришли.

Бьём на максимально атомарные блоки!

NB: это и есть суть БЭМ, то, что многие не понимают.

Погружаясь вглубь DOM, нужно стараться создавать новые и новые блоки, а не строить связи родитель__элемент__элемент.

Вспоминаем как мы это делаем:

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

HTML: как правильно вкладывать блоки в блоки?

<div class="b-blog">
    <div class="b-blog_item b-post">
    </div>
</div>
        

Миксование создаст связь между блоками!

В этой DOM-ноде смешиваются стили от 2-х разных блоков:

Эти стили объединяются в одном html-элементе и создают таким образом связи между блоками.

CSS: как правильно вкладывать блоки в блоки?

.b-blog {
  // блок 
  @at-root .b-post {
    // ещё один блок 
  }
}

Скомпилируется в:

.b-blog {
  /* стили блока */
}
.b-post {
  /* ещё один блок */
}

Мы написали вариант #1: микс элемента родителя + новый блок

Позиционирование — на элементе родителя и блоке родителя, стили блока — на новом блоке.

<div class="b-blog">
    <div class="b-blog_item b-post">
    </div>
</div>
        

Как можно было по-другому?

#2: Микс блоков и сетки

Позиционирование — на классах сетки, стили блоков — на самих блоках.

<div class="b-blog b-grid">
    <div class="b-grid__col b-post">
    </div>
</div>
        

#2.1: Не жалеем div: блоки внутри сетки

Позиционирование — на классах сетки, стили блоков — на самих блоках.

<div class="b-blog">
    <div class="b-grid">
        <div class="b-grid__col">
            <div class="b-post">
            </div>
        </div>
    </div>
</div>
        

#3: Блоки-врапперы (l-, h-)

Позиционирование — на блоках-врапперах.
Связей между блоками (блок—элемент) больше нет!

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

<div class="l-blog">
    <div class="b-blog">
        <div class="l-post">
            <div class="b-post">
            </div>
        </div>
    </div>
</div>
        

Можно добавить микроформатов/микроданных

Это не нужно для БЭМ, просто я люблю микроформаты, Гугл любит микрофрматы и Яндекс тоже любит микроформаты :) Классно что мы можем добавлять любые имена классов куда-угодно, все стили у нас — только на БЭМ-классах.

Мы написали BEM-дерево:

<div class="block1">
    <div class="block1__elem1 block2">
        <div class="block2__elem1"></div>
    </div>
    <div class="block1__elem2"></div>
</div>
    

Нет каскада:

.block1 {}
.block1__elem1 {}
.block1__elem2 {}
.block2 {}
.block2__elem1 {}
    

Модификация

6 видов

  1. Модификатором
    • модификатором блока
    • модификатором элемента
  2. Контекстом (т.е. каскадом от блока выше)
  3. Уровнем переопределения (добавлением-перезаписью файла стилей)
  4. Миксованием (добавлением классов других блоков)
    • включая глобальный класс

Просто добавляйте модификатор!

<div class="block-name__elem_key_value">
    

А для элементов — делай каскад от модификатора.

Модификаторы для элементов, можно?

Если речь идет о простых правках, типа «активный пункт меню», то да, можно:

<a class="menu__link menu__link_state_active">
    

Булевые модификаторы

Кстати в таких простых случаях, можно писать модификаторы просто одним словом:

<a class="menu__link menu__link_active">
    

Но подумайте, может это новый блок?

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

БЭМ допускает ошибки

Самые популярные ошибки

1. block__el__el

Например, слайдеры очень часто верстают дикой вложенностью.

2. Повышение специфичности

В html как-будто всё ok:

<div class="block">
  <div class="block__el">
    

А на деле сели в машину и сгорели:

/* CSS */
.block .block__el {}
    

3. Стили вне блоков

<ul class="menu checkoutForm big myfuckingclass-bold">
    

Почему это ошибки?

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

Классификация ошибок BEM CSS

от Александра Корецкого @n2j7 из Prom.ua

Проблемы со стилями:

Ошибки разработчиков:

Ошибки разработчиков:

Как мне?...

Вывести текст из WYSIWYG?

Как назначаются стили для типографики? Не будешь же назначать каждому тегу какой-то класс?

Artur Kornakov, @fliptheweb

Добавить .b-text блоку родителю

И использовать каскад.

.b-text h2 {}
.b-text p {}
.b-text img {}
.b-text ul li {}
    

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

Как писать BEM CSS в Sass

.b-list {
  /* стили блока  */
  //…
  &__item {
    /* стили элемента */
  }
  &__link {
    /* элемент #2… */
  }
}

Скомпилируется в:

.b-list {
  /* стили блока  */
}
.b-list__item {
  /* стили элемента */
}
.b-list__link {
  /* элемент #2… */
}

Sass: модификаторы блоков

.b-list {
  /* стили блока */
  &--style_numered {
    /* стили модифицированного блока */
  }
}

Скомпилируется в:

.b-list {
  /* стили блока  */
}
.b-list--style_numered {
  /* стили модифицированного блока */
}

Sass: модификаторы элементов

.b-list {
  /* стили блока */
  &__item {
    /* стили элемента */
    &--active {
      /* стили модифицированного элемента */
    }
  }
}

Скомпилируется в:

.b-list {
  /* стили блока */
}
.b-list__item {
  /* стили элемента */
}
.b-list__item--active {
  /* стили модифицированного элемента */
}

Sass: модификация элемента от модификатора блока

.b-list {
  $rootParent: &;
  &__item {/* обычный элемент */}
  &--style_numered {/* модифицированный блок */
    #{$rootParent}__item {
      /* элемент модифицированного блока */ 
    }
  }
}

* Это разрешённая практика в БЭМ, но изменение стилей не должно быть монструозным.

Скомпилируется в:

.b-list {
  /* стили блока */
}
.b-list__item {
  /* стили элемента */
}
.b-list--style_numered b-list__item {
  /* стили элемента модифицированного блока */
}

Модификация элемента элементом? bad practice, но…

.b-list {
  $rootParent: &;
  &__item {/* элемент */}
  &__link {/* элемент */
    #{$rootParent}__item--active & {
      // наглый модификатор элемента 
    }
  }
}

* Так делать неправильно. Модификация элемента элементом — нарушение правил! Но бывает нет выхода.

Скомпилируется в:

.b-list {/* блок */}
.b-list__item {/* элемент */}
.b-list__link {/* элемент */}
.b-list__item--active .b-list__link {
  /* наглый модификатор элемента */
}

Как «правильно» модифицировать блоки (внешний вид) от контекста?

  1. Можно юзать каскад, но это тонкая работа — для случая «перебить чуть-чуть стилей, ведь этот блок нам не понадобится переносить в изменённом виде куда-то отдельно».
  2. Добавить модификатор блоку — просто и надежно, но не создает логической связи между блоком-родителем и вложенным в него блоком, что должен изменятся.
  3. Использовать миксование: создать элемент родителя, навесить на него нужные стили и смиксовать с вложенным блоком.

Спрашивайте: ru.bem.info/forum

Пример переверстки по БЭМ (упрощенный)

БЭМ — это методология, не реализация.

Яндекс-БЭМ (Full Stack BEM)

Виталий Харисов

Сергей Бережной

Пример кода Яндекс-БЭМ

Верстаем надпись «Привет», input и кнопку.

Надпись, input и кнопка

Пример кода Яндекс-БЭМ

({
  block : 'page',
  title : 'hello',
  head : [
    { elem : 'css', url : 'hello.min.css' }
  ],
  scripts : [{ elem : 'js', url : 'hello.min.js' }],
  mods : { theme : 'islands' },
  content : [
    {
      block : 'hello',
    

Верстаем-верстаем, это BEMJSON

content : [
  {
    block : 'hello',
    content : [{
        elem : 'greeting',
        content : 'Привет, %пользователь%!'
      },{
        block : 'input',
        mods : {theme : 'islands', size : 'm'},
        name : 'name',
        placeholder : 'Имя пользователя'
      },
    

Осталось кнопочку добавить…

      {
        block : 'button',
        mods : {theme : 'islands', size : 'm',
                type : 'submit'},
        text : 'Нажать'
      }
    ]
  }
]
})
    

Это ещё не всё.

Тепер надо написать BEMHTML.

block('hello')(
    js()(true),
    tag()('form')
);
    

Кстати CSS и JS тоже надо писать

Даже разработчики Google Material Design не смогли с первого раза правильно написать имена классов по БЭМ :)

Диалекты БЭМ

OPOR

Артем Сапегин

OPOR

Известный пример использования методологии БЭМ сторонним разработчиком - Артёмом Сапегиным.

.logo {color: saddlebrown;}
.page_about .logo {color: ghostwhite;}
social-button i {}
<div class="social-button"><i></i></div>
.scrollable
a.fake
.is-expanded
.js-select
.header
  .header-i
    

BEViS

Вадим Макишвили

BEViS

Диалект БЭМ, с более строгими правилами для максимальной надежности верстки, придуманный Вадимом Макишвили для Яндекс.Карт.

Нет миксов.
Нет модификаторов.
Есть состояния:

<div class="popup _orientation_top"></div>
<button class="button _pressed _focused"></div>
.button._pressed {}
    

BEMIT

Гарри Робертс и Николас Галлахер

BEMIT: пространства имен

Продвинутое использование префиксов и суффиксов от Гарри Робертса. Попытка описать взаимосвязь между независимыми блоками с точки зрения SMACSS и OOCSS.

<div class="o-media@md  c-user  c-user--premium">
  <img src="" class="o-media__img@md  c-user__photo" />
  <p class="o-media__body@md  c-user__bio">...</p>
</div>
    

БЁМ

Роман Комаров

БЁМ: шутка всерьез

БЭМ в котором можно писать как хочешь. Хоть с элементами элементов.

.block__element__subelement
    

Теперь я использую БЁМ — это примерно как БЭМ, только вы можете писать его как хотите, а не как укажет партия или церковь. Ура!

Роман Комаров

Префиксы

Префиксы

Были в раннем БЭМ. Сейчас пропагандируются Гарри Робертсом и используются многими не-Яндекс разработчиками. Используются для создания своего пространства имен и логического разделения блоков.

Префиксы

b-,
l-,
g-,
i-,
h-,
m-,
c- и js-,
qa-,
o-,
c-(другой :),
u-,
t-,
s-,
is-,
has-

Синтаксис

Стиль Гарри Робертса

Многим нравится зарубежный формат модификаторов, через --, он читабельней.

<a class="block-name__element-name--state_active">

Стиль camelCase

А через camelCase – ещё читабельней!

<a class="blockName__elementName--state_active">

Стиль без подчеркиваний

Некоторые идут ещё дальше и заменяют __ на -. camelCase единственный гарантирует что вы поймете где блок, а где элемент.

<a class="blockName-elementName--state_active">

Сокращенные модификаторы

Сокращенные модификаторы

Зарубежом их назвали „Individual modifiers: a shorter syntax“. У нас перевели как «Обособленные модификаторы: сокращенный синтаксис». Яндекс в официальной документации называет их «Стиль No-namespace».

<div class="blockName__elem -key_value">
.blockName {
  &__elem {
    &.-key_value {
    }
  }
}
    

— Теряем миксы блоков с модификаторами!
— Не можем использовать Full BEM Stack!

JS-блоки

JS-блоки

$('.js-fancybox').fancybox();
    
Это миксование css-блока и js-блока на одной dom-ноде. Канонический БЭМ считает, что они не нужны, т.к. js-функционал нет смысла отделять от блока. Гарри Робертс и не-Яндекс разработчики их активно используют и пропагандируют: т.к. разделение позволяет легко копировать css-блок без связанного с ним JS.

Google MDL

Google MDL

Библиотека блоков от Google, css-реализации их Material Design придуманного для Android.

<!-- Accent-colored raised button with ripple -->
<button class="mdl-button mdl-js-button>
                  mdl-button--raised>
                  mdl-js-ripple-effect>
                  mdl-button--accent">
  Button
</button>
    

Госдеп

U.S. Goverment: 18F BEM

.accordion
.accordion-item
.accordion-item-selected
 
.nav_bar
.nav_bar-link
.nav_bar-link-clicked
    

BEML / posthtml-bem / BEMto

BEML

Препроцессор BEM для HTML через Grunt/Gulp

<div block="b-animals">
  <div elem="cat" mod="size:big, color:red"></div>
</div>
    

posthtml-bem

Препроцессор BEM для HTML через PostHTML.
Синтаксис почти такой же, но с отличиями!

<div block="MadTeaParty">
  <div elem="march-hare" mods="type:mad">March Hare</div>
  <div elem="march-hare" mods="mad">March Hare</div>
</div>
    

Please use "mods" for the attribute modifiers instead of "mod" and a space as a separator of modifiers instead of a comma.

BEMto

Написание BEM в Jade.

+b.block1
  +e.element1 Foo
  +b.block2
    +e('a')(href="#bar").element Bar
  +e.element2 Baz
    

Full BEM Stack в HTML

Вы можете создавать свои гайдлайны

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

bem.info

getbem.com

Это всё БЭМ

Методология и реализации

Реализации БЭМ:

BEM is like Agile

Роберт Харитонов

MCSS → BEM

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

Роберт Харитонов

Джонатан Снук

SMACSS → BEM

Most common misspelling is “SMACCS”.
I should just rename it to BEM.

Jonathan Snook

ru.bem.info/
forum/

Slack WSD
/bem

Пробуйте!

%Company% BEM

Это всё БЭМ

Тонкости БЭМ

БЭМ включает в себя много техник

Кое-что мы с вами обсудили/упомянули:

Но многое осталось за кадром

Читать дальше

…и дальше

Спасибо!

EPAM logo

Igor Zenich
EPAM

Презентация: bit.ly/bem-css-guide

Powered by Shower