Удобный БЭМ
Приветствую. В этой статье я расскажу, как можно изменить БЭМ, сохранив лучшие его черты и избавившись от худших.
Итак, сначала поговорим о том, что не так с БЭМ? Может, ничего не надо менять и все и так хорошо?
БЭМ — это методология, позволяющая использовать CSS/HTML/JS много раз. Она вводит понятия блока, элемента, модификатора и микса. Начав ее использовать, ты понимаешь, что это именно то, чего ты ждал много лет, это так удобно, понятно и красиво! Но спустя некоторое время начинают встречаться такие моменты в разработке, которые решить с помощью БЭМ можно, но это не приносит ни удовольствия, ни, главное, пользы. О чем я говорю? Пройдемся по таким моментам:
1. Одноразовые блоки и элементы
Данная проблема так сильно мне надоела, что заставила написать эту статью.
Понятие блока подразумевает сущность, которую можно и нужно переиспользовать, однако на практике создается большое количество блоков, которые применяются один раз.
Например, нам нужно сделать следующее: расположить на странице заголовок, за ним — текстовое поле и кнопку отправления ввода, так, как показано на картинке:
Что мы сделаем в соответствии с БЭМ? Есть несколько вариантов:
- Создать блок формы и его элементы: заголовок, кнопку, текстовое поле
- Создать отдельно блоки для каждого из компонентов (кнопка, текстовое поле, заголовок), а также для формы
- …
Какой бы мы ни выбрали, у нас возникнет проблема: как задать отступы между всеми этими блоками?
Если мы выбрали первый вариант, то можно решить задать отступы для элементов формы, ведь это не противоречит методологии. Однако в этом случае мы уничтожаем суть блока: он не может быть переиспользован, так как его внутренняя разметка подойдет только к текущей ситуации.
Если бы мы выбрали второй вариант, тогда можно было бы примиксовать к форме какой-нибудь блок, а элементы этого блока примиксовать к компонентам формы. И, соответственно, для элементов только что созданного блока задать отступы. И вот тут-то и проявляется проблема одноразовых блоков: они создаются для использования только в одном месте! Их больше нельзя использовать, потому что на других страницах компоненты будут расположены по-другому.
Данная проблема порождает одноразовые блоки/элементы, а также модификаторы типа блок__элемент_size_размер
или блок__элемент_place_место-где-будет-расположен-блок
(для задания отступов), которые, как уже было сказано, используются один раз и загромождают как файлы разметки, так и проект собственными директориями и файлами.
То же самое касается не только отступов, но и размеров блоков (для кнопок, например, это часто тянет за собой изменение еще и line-height
'ов), размеров шрифтов, внутренних отступов и т.д.
2. Длинные имена классов
Тут даже рассказывать особо не о чем. Не думаю, что кому-то нравится разметка, которая.выглядит примерно так:
Select a sector, please:
3. Значения по-умолчанию или темы блоков
Предположим, у нас есть блок кнопки. Нужно её стилизовать в соответствии с требованиями дизайна. Но в другом проекте тоже будет класс кнопки. Она будет выглядеть по-другому, однако некоторая часть стилей будет одинакова. Что советует делать БЭМ? Он говорит создать модификатор темы и задавать его всем требуемым элементам.
Но при таком подходе получится следующее:
Это загромождение кода, и это плохо.
Критикуешь — предлагай
Что я предлагаю, чтобы исправить это безобразие? Я предлагаю следующий манифест, который, по сути, является надстройкой над стандартным БЭМ.
Манифест — Improved BEM
П.1 Слой модулей и слой страницы
Я предлагаю разбить стилевое оформление на две части:
Первая часть — слой модулей (components layout). Эта часть пишется в соответствии со всеми (почти*) правилами БЭМ. Она задает стили для переиспользуемых блоков, или, лучше сказать, компонентов, например, для кнопки, текстового поля, заголовка и т.д.
Другая часть — слой страницы (page layout). Он требуется для задания стилей блоков и элементов конкретной страницы. Соответственно, эти блоки/элементы будут использованы один раз (во всяком случае, на одной странице). Здесь правила БЭМ не действуют. Выглядит это так:
Файл: index.css
.___send-button {
margin-bottom: 2px;
font-size: 13px;
}
.___message-textarea {
width: 240px;
height: 300px;
font-size: 14px;
}
Имя файла page layout’а выбирается произвольно. Главное, чтобы оно соответствовало сути страницы. Все стили начинаются с '___', чтобы их нельзя было спутать с классами стандартных сущностей БЭМ. Также классы не привязаны к БЭМ-сущностям — их имена лишь отражают то, к чему они должны применяться. Ещё стоит заметить, что все стили page layout’а располагаются в одном файле, так как относятся к одной странице.
Данное разделение позволяет решить первую проблему, при этом не нанеся ущерба главной цели БЭМ — создания стилей/разметки так, чтобы их можно было переиспользовать. Данные стили будут применяться только на одной странице и никоим образом не будут мешать стилям компонентов из components layout. Таким образом, мы избавляемся от одноразовых классов, сохраняя возможность переиспользовать блоки и не нарушая областей видимости.
Также имеет смысл разделить components и page layout’ы и на уровне директорий.
*кроме правил, которые отменяются следующими пунктами манифеста.
П.2 Длинные имена классов
(Экспериментальный, поэтому опциональный пункт*)
Предлагается заменить часть стандартной системы именования на следующую:
Для блока: class="блок"
(без изменений)
Для блока с модификатором: class="блок _модификатор"
(обращение через комбинированный селектор .блок._модификатор
)
Для элемента: class="блок__элемент"
(без изменений)
Для элемента с модификатором: class="блок__элемент _модификатор"
(обращение через .блок__элемент._модификатор
)
Данный пункт позволяет получать краткий код в отношении модификаторов. Очевидно, почему нельзя сделать то же самое с элементами.
Важно, чтобы в файлах со стилями не было правил, заданных для селекторов, которые состоят только из модификаторов:
/*Неправильно!!!*/
._active {
background-color: #abcdef;
}
*подобное именование модификаторов может привести к проблемам на блоках/элементах, смиксованных с другими блоками/элементами, при условии, что обе сущности могут иметь одинаковый модификатор. То есть, задавая модификатор для одной сущности, мы задаем его для всех примиксованных к этому узлу.
П.3 Значения по умолчанию и темы
Тут все просто. Предлагается выбрать тему по умолчанию, но прописывать стили для нее не в классе блока, который находится в файле блока, а в классе блока, который следует разместить в файле с темой. Например:
Файл — button/button.css
.button {
cursor: pointer;
display: inline-block;
}
Файл — button/_theme/button_theme_P2.css
.button_theme_P2,
.button {
border-radius: 3px;
border: 1px solid #f00;
}
Или в соответствии с п.2
.button._theme_P2,
.button {
border-radius: 3px;
border: 1px solid #f00;
}
Таким образом, данная тема становится стандартной, но при желании можно использовать её непосредственно.
Итог
Данный манифест призван решить некоторые проблемы, возникающие при верстке в соответствии с БЭМ. Основной его составляющей было разбиение на components layout и page layout. Хотя выглядит манифест достаточно революционно, неканонично и смело, заявленные проблемы он решает. Использовать его весь, частично или не использовать вообще — решать, конечно, вам.
P.S. Если вы сейчас гневно проскроллили всю страницу чтобы поставить минус, не забудьте написать комментарий, иначе пользы ваш минус не принесет (как и манифест).