Статус: черновик.
БЭМ это не именование классов по определенному шаблону. Именование классов лишь способ достижения цели — «модульной верстки»
- Для небольших студий, у которых не один большой, а множество средних проектов
- Фрилансера с маленькими сайтами
- Для лендингов
- И даже когда вы делаете правки в чужом спагетти-коде - вы можете (и должны) примерять BEM!
- Всем остальным :)
БЭМ-методология: с чего всё начиналось и зачем это всё нужно
БЭМ был придуман для решения одной проблеммы «ухода от css каскада».
Все из-за того что CSS имеет глобальную область видимости, что очень плохо.
Идея убрать каскад кажется дикой - как, это же каскад. У нас каскадные таблицы стилей! Каскад сверху до низу по всей странице! Мы в детстве 2000-х играли в игру "кто напишет меньше тегов"!
Но. У нас страница состоит из блоков. Независимых блоков. Ее части не есть один большой текст, со стилями что спускаются вниз. Это блоки, что могут и должны иметь возможность переноситься.
Все правила БЭМ нужны только для этого, и если вы будете думать что изобрели «свой более лучший БЭМ» остерегайтесь, вы за это больно поплатитесь.
Главное в BEM - понятие независимого блока.
Независимый блок (НБ или просто блок) это самодостаточный элемент страницы, который при перемещении в другое место на странице или на другую страницу не теряет своей самодостаточности.
"Как его таким написать?" Просто писать стили тупо на каждый блок. BEM хорош тем, что позволяет не забивать голову ерундой с каскадом, а сосредоточимся на семантике и логике кода. А с препроцессорами BEM позволяет писать еще и очень чистый и логичный код. Но про это чуть позже.
Как проверить? Просто навести на блок в инспекторе кода. У него не должно быть каскада.
Элемент – это часть блока, отвечающая за отдельную функцию. Он может находиться только в составе блока и не имеет смысла в отрыве от него.
Элемент можно представить себе как папку в файловой системе, это способ организации кода, чтобы было понятно, что к чему относится.
БЭМ-сущность, определяющая внешний вид, состояние и поведение блока или элемента.
Использование модификаторов опционально.
По своей сути модификаторы похожи на атрибуты в HTML. Один и тот же блок выглядит по-разному благодаря применению модификатора.
Например, внешний вид блока меню (menu) может меняться в зависимости от примененного модификатора.
<ul class="b-list">
<li class="b-list__item">
<a class="b-list__link">
<i class="b-list__link__icon"></i>Text here
</a>
</li>
</ul>
<ul class="b-list">
<li class="b-list-item">
<a class="b-list-link">
<i class="b-icon"></i>Text here
</a>
</li>
</ul>
<ul class="b-list">
<li class="b-list__item">
<a class="b-list__link">
<i class="b-list__icon"></i>Text
<span class="b-map__link">here</span>
</a>
</li>
</ul>
.b-header
display block
font-size 12px
.b-link
color red
&:hover
color green
.b-header
display block
font-size 12px
.b-tabs__tab
width 100%
.b-list__item_type_goodbye-my-eyes
background red
color green
.b-list__link
color purple
<ul class="b-list">
<li class="b-list__item">
<a class="b-list__link">
<i class="b-list__icon"></i>Text here
</a>
<ul class="b-list">
<li class="b-list__item">
<a class="b-list__link">
<i class="b-list__icon"></i>Text here
</a>
</li>
</ul>
</li>
</ul>
<ul class="b-main-menu active"></ul>
.b-main-menu.active
color red
var panel = $('.b-panel');
// vs
var panel = $('.js-panel');
<ul class="b-list h-mt-20 h-mb-50 h-pointer h-left h-color-red">
<li class="b-list__item">
<a class="b-list__link h-fs-25">
<i class="b-list__icon"></i>Text
</a>
</li>
</ul>
.b-list_float_left
float left
<ul class="b-list">
<li class="b-list__item">Text</li>
<li class="b-list__item2">Text</li>
<li class="b-list__item3">Text</li>
<li class="b-list__item4">Text</li>
</ul>
.b-list__item
.b-list__item2
.b-list__item3
.b-list__item4
color red
.b-list
list-style none
.b-list__item
display block
.b-list__link
color red
.b-list
list-style none
li
display block
a
color red
.b-list
.b-list__item
.b-list__item-name
.b-list__item-link
.b-list__item-icon
.b-list__item-delim
.b-list__item-panel
.b-list
.b-item-list
<ul class="b-list">
<li class="b-list__item">
<a class="b-list__link">
<i class="b-list__icon"></i>Text
</a>
</li>
</ul>
<ul class="b-list">
<li class="b-list__wrapper">
<a class="b-list__panel">
<i class="b-list__star"></i>Text
</a>
</li>
</ul>
Для стилей удобно использовать Parent selector «&» он есть во всех популярных препроцессорах
.b-list
list-style none
&__item
display block
&__link
color red
&__item_active &__link
color blue
Кроме того с недавних пор в stylus появился «Partial Reference» это что то вроде Parent parent selector
.foo
&__bar
width: 10px
^[0]:hover &
width: 20px
трансформируется в
.foo__bar {
width: 10px;
}
.foo:hover .foo__bar {
width: 20px;
}
Название блока используется только один раз
Оно объявляется на первом уровне и нигде больше не повторяется. Исключения могу составлять только сложные случаи модификаторов. Однако, если вам это понадобилось, то скорее всего, стоит пересмотреть структуру элементов и модификаторов. Уверен, что найдётся способ упросить блок или декомпозировать его.
.block
// стили блока
Элементы идут на втором уровне вложенности
.block
// стили блока
&__element
// стили элемента
&__title
Иногда названия элементов будут причудливым образом сочетаться и захочется вложить один селектор элемента в другой. Не поддавайтесь этому искушению несмотря на то, что будет генерироваться правильный CSS.
.block
&__element
&-wrapper
// Пример плохого элемента.
// Его будет трудно отыскать.
Никогда не делайте подобного. Такой селектор очень трудно будет найти в коде. В примере название элемента element-wrapper разорвано на две части. Пишите название элементов полностью даже если они частично повторяют уже существующие.
Псевдо-классы, псевдо-элементы и модификаторы элементов допускается писать на третьем уровне вложенности
.block
&__element
&_modifier
// стили модификатора элемента
&_modifier_value
// модификатор со значением не разбиваем на части
&:hover
// псевдо-класс — это тоже модификатор
Стили элемента и его вариации группируются естественным образом, что позволит быстрее их локализовать в исходном коде.
Принято, что модификатор элемента не влияет на другие элементы. Располагая их на третьем уровне иерархии, мы защищаемся от возможных ошибок. Могу предположить ситуацию когда некоторые модификаторы будет удобнее расположить на втором уровне, продублировав название элемента.
.block
&__element_active
// модификатор элемента на втором уровне
&__element_modifier_good
// пример модификатора со значением
На практике мне больше нравится именно такая запись — модификатор на втором уровне. Также считаю, что недопустимо разбивать название модификатора на части, а так же не стоит отделять значение модификатора от его названия. Излишняя структурированность может ухудшить читаемость. Легко потерять текущий контекст. Помните об этом.
Модификаторы блока могут участвовать в каскаде и располагаются на втором уровне
Модификаторы блока принято использовать, чтобы повлиять на внешний вид самого блока и его дочерних элементов, но не вложенных в него других блоков.
.block
background white
&__title
color black
font-weight bold
&_featured
background black
&_featured &__title
color white
font-size 30px
Изящность кода чуть теряется из-за того, что нам важно сохранить значение &. Как только мы перейдём на следующий уровень вложенности, то использовать его в названии элемента уже не сможем — нужно будет писать полное название селектора вместе с названием блока, чего мы всячески избегаем.
.block {
background: white;
}
.block__title {
color: black;
font-weight: bold;
}
.block_featured {
background: black;
}
.block_featured .block__title {
color: white;
font-size: 30px;
}
Для обозначения БЭМ-сущностей зачастую используется специальный формат строки, по которой можно однозначно определить, какая именно сущность представлена.
В оригинальном стиле такая строка будет выглядить следующим образом:
block[_blockModName[_blockModVal]][__elemName[_elemModName[_elemModVal]]]
(В квадратных скобках необязательные параметры)
block-name
— блок.block-name_mod-name_mod-val
— модификатор блока в формате ключ-значение.block-name_mod
— булевый модификатор блока.block-name__elem-name
— элемент блока.block-name__elem-name_mod-name_mod-val
— модификатор элемента в формате ключ-значение.block-name__elem_mod
— булевый модификатор элемента.