1. 17. 11. Алгоритм выделения блоков
Чтобы избежать типовых ошибок использования БЭМ, предлагаем идти по следующей схеме:
Шаг 1
По умолчанию всё — блоки, каждый фрагмент макета — это отдельный уникальный блок. Продемонстрируем на примере двух немного отличающихся карточек. В первом случае кнопки расположены друг под другом, во втором — рядом.
Создаём для всего отдельные блоки. Возможно, блоки будут схожи, они будут повторять друг друга целиком или частично, но мы пока что на это не обращаем внимания. Оставляем это всё на потом.
Шаг 2
Начинаем уточнять, этот блок независимый или нет, используется только самостоятельно или в составе других блоков. Если объект не может существовать отдельно от родителя, то это элемент. Если внутренняя часть будет переиспользоваться, то это блок.
Но всё ли так однозначно и просто в том, чтобы отделить блоки от элементов. Разберём на практике.
У нас есть макет лендинга, который состоит больше, чем из одной страницы, и, как у любого лендинга, у главной страницы есть множество разделов. Каждый из этих разделов со своим заголовком. Визуально эти заголовки практически идентичны: шрифт, размер совпадают. Заголовки различаются только цветом, светлый на контрастном фоне и тёмным, если фона нет.
Следовало ли сделать заголовок раздела отдельным независимым блоком?
Аргументы «За» независимый блок:
С одной стороны, это соответствовало бы духу БЭМ: заголовки повторяются, их код идентичен.
Если нам скажут, что заголовки нужно увеличить, было бы удобно делать это из модуля заголовка.
Аргументы «Против» независимого блока:
Заголовок не может использоваться отдельно от раздела, заголовки вообще не функциональны в отрыве от того, что они озаглавливают.
Может измениться заголовок только одного раздела, в этом случае лучше, чтобы это был элемент блока Раздел.
В случае с заголовком стилей совсем мало. Это не кнопка, у которой есть состояния, обнуление свойств по умолчанию, фоны и обводки, иконки, логика и скрипты для поддержки этой логики. Это просто фрагмент текста с параметрами шрифта, у него нет никаких пользовательских действий или чего-то подобного.
Для небольшого лендинга и проекта, который не планируется развивать, можно оставить заголовки элементами, не выделять их в отдельный блок. Кода, который при этом придётся повторить в отдельных блоках, очень мало, это только параметры шрифта.
При этом нельзя утверждать, что для настоящего проекта такое решение было бы правильным.
У крупных проектов обычно бывает «дизайн-система» или UI-kit, в который попадают такие системные элементы, как кнопки, заголовки разных видов, карточки, списки, возможно — цитаты, другие текстовые элементы, даже виды абзацев. Если бы наш макет был для такого случая, то, вероятнее всего, заголовок был бы блоком.
Если вы хорошо разобрались, что такое блок и что такое элемент, как сочетать эти две БЭМ-сущности на одном HTML-элементе, следующие два шага можно объединить.
Шаг 3
Добавляем элементы для внешней модификации вложенных блоков. Это могут быть внешние отступы, размеры, выравнивания и другие. Сперва упростим себе задачу и элементы добавим как обёртки над вложенными блоками. Для первого вида карточек у каждого вложенного блока с кнопкой будет своя обёртка, для второго обёртка будет одна, в ней нам нужно выстроить кнопки в ряд.
Карточка первого типа:
Карточка второго типа:
Шаг 4
Оптимизируем разметку блоков, используем миксование и убираем лишние обёртки.
Где это возможно, один HTML-элемент будет одновременно и блоком и элементом. В нашем примере миксование можно использовать только для карточек первого типа. Для карточки второго типа всё остаётся без изменений.
Шаг 5
Анализируем блоки/элементы, смотрим и выявляем одинаковые.
Это то действие, которое мы отложили на потом в Шаге 1.
Если мы видим, что блоки схожи, изменяются параллельно, можно слить их в один блок и переиспользовать его. Самый частый вид блока — это базовый блок, от которого будем модифицироваться. Если блок менее распространён — это модификатор блока. Так наши уникальные блоки становятся уже не уникальными и могут использоваться снова и снова.
Карточка первого типа:
Карточка второго типа:
И в конце покажем карточки того и другого типа на действующих сайтах.
Разберём ещё несколько случаев на практике.
К примеру, у нас есть два раздела Преимущества работы с нами и Категории товаров, которые очень похожи (заголовки, сетка), но есть и ряд отличий.
Возможны три варианта реализации этого кейса:
Взять блок Преимущества работы с нами, его модифицировать, убрать специфические свойства, превратить в базовый (абстрактный) класс
section
. Для свойств, которые убрали из базового класса добавить модификатор — это будет реализация для блока Преимущества работы с намиsection section--profit
. Для блока Категории товаров использовать другую модификацию базового классаsection section--category
. Правда со временем могут возникнуть проблемы при изменении (рефакторинге), полезут баги, потребуется всё снова тестировать. Как итог, больше потраченного времени.Взять блок Преимущества работы с нами за основу, без изменений класс
section
. А для блока Категории товаров сделать модификатор. Появятся дублирующие свойства, которые переопределяются для блока Категории товаров классsection section--category
. Из минусов — сложнее переопределять существующие стили, появится лишний код.Взять блок Преимущества работы с нами (
profit
), полностью его скопировать и назвать копию блоком Категории товаров (category
), внести правки в стили. То есть мы просто создаём копию блока. Этот способ самый быстрый и дешёвый. Но при таком подходе сильно раздувается кодовая база.
Замечание
Базовый класс (базовый блок) — это класс с минимальным количеством свойств. Необязательно базовый блок будет полностью самодостаточным блоком, который может быть блоком без каких-либо модификаторов.
Ещё один пример, форма с настройками профиля пользователя.
Управляющие элементы: поля для ввода, выпадающие списки, многострочное поле для ввода имеют одинаковое оформление (шрифт, отступы, граница). Помимо стандартного набора свойств, эти элементы содержат и специфические, характерные только для этого элемента управления CSS-свойства. У многострочного поля для ввода есть CSS-свойство resize
, которое помогает не сломать сетку (resize: vertical;
). У выпадающего списка select
есть отдельные свойства для стилизации стрелки вниз.
Как лучше поступить в этом случае?
Можно каждый управляющий элемент вынести в отдельный блок и стилизовать независимо.
Стилизация каждого отдельного компонента не повлияет на другие — это плюс, но в общем стилевом файле будет дублирование кода, а это уже минус.
А можно использовать комбинацию блоков. Создать общий блок form-control
— базовый блок для элементов управления. Он будет содержать только базовый набор CSS-правил, которые есть у всех контролов. Все тонкости стилизации отдельных элементов формы описываются в блоках соответствующих элементов управления.
Шаг 6
Анализируем функциональность блока и следим за тем, чтобы он не стал «жадным».
Если класс для блока, помимо общих стилей, содержит декоративные стили, сеточные стили и другие, смотрим, можно ли поделить этот блок на несколько так, чтобы по возможности один блок отвечал за что-то одно (один блок-одна функция).
К примеру, создаём блок, который отвечает только за сетку; блок, который отвечает за внешний вид содержимого; блок, который отвечает за выравнивание. И всё это будут разные блоки.
Руководствуемся правилом: «Лучше добавить лишние классы, а потом удалить, если они не понадобятся».
Last updated