Hacknote.js

Мифология БЭМ

4 мин.
Мифология БЭМ

Среди разработчиков распространён миф, что БЭМ — это просто довольно некрасивый и чрезмерно длинный способ нейминга CSS-классов, который не очень-то актуален в современной разработке ввиду наличия во фронтенд-экосистеме огромного количества более удобных инструментов, полностью заменяющих его. На самом деле, это в корне неверное суждение, поскольку БЭМ — это нечто большее, чем просто нейминг, и, на мой взгляд, он может быть полезен любому веб-разработчику независимо от технического стека.

Зачем мне БЭМ, если есть «framework-name»?

Часто возникают споры о том, что лучше использовать для вёрстки: БЭМ или, например, Tailwind . В пользу каждого из вариантов выдвигается множество довольно рациональных аргументов, поэтому однозначного победителя в таких спорах зачастую не возникает. И дело даже не в том, что оба этих инструмента так хороши. На самом деле, нюанс заключается в том, что БЭМ — это более высокоуровневая абстракция, чем просто фреймворк для вёрстки, поэтому сравнение в данном случае просто не имеет смысла.

БЭМ — в первую очередь методология разработки, а конкретные способы и инструменты, реализующие принципы этой методологии, абсолютно опциональны. Разрабатывать приложение по БЭМ можно и с помощью Tailwind, и с помощью любого другого фреймворка/библиотеки. Более того, его можно применять не только в веб-разработке.

БЭМ — про нейминг CSS-классов

Согласно БЭМ CSS-классы действительно именуются по схеме block__element_modifier (разделители можно выбрать на свой вкус). Многие на этом заканчивают изучение этой методологии и идут писать код на Tailwind. На самом же деле нейминг — это просто один из тех самых опциональных инструментов, использования которого не достаточно для следования методологии.

/* Блок */
.my-button {/* ... */}
/* Элемент */
.my-button__label {/* ... */ }
/* Модификатор */
.my-button_primary {/* ... */ }

Такие длинные названия классов позволяют исключить использование каскада (превратив CSS в SS), что в некоторой степени упрощает жизнь, поскольку пропадает необходимость думать о специфичности селекторов, поскольку у всех селекторов она будет одинакова, и появляется возможность сфокусироваться исключительно на семантике. Кстати, браузеру тоже не нужно будет тратить время на применение каскада, что немного повысит производительность CSS.

На практике же можно писать каскадные селекторы вида .block .element .modifier и продолжать следовать БЭМ, что заставит вас задумываться о каскаде и добавит риск возникновения классов с такими же названиями (инструменты вроде Styled Components или CSS Modules исключают этот риск), но основная суть останется та же.

Если используемый вами инструмент позволяет вам использовать более удобный на ваш взгляд нейминг, можете запросто использовать его. Например, вот так я пишу стили по БЭМ с использованием Styled Components :

import styled, { css } from "styled-components";
/** Модификаторы */
const buttonKindStyles = {
primary: css`
/* ... */
`,
secondary: css`
/* ... */
`
};
/** Блок my-button */
export const MyButton = styled.button`
/* ... */
/** Выбор модификатора: my-button_primary или my-button_secondary */
${({ kind }) => buttonKindStyles|kind]}
`;
/** Блок my-form */
export const MyForm = styled.form`
/* ... */
/** Элемент my-form__button */
${MyButton} {
/* ... */
}
`;

В чём же тогда всё-таки смысл БЭМ?

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

Предположим, вы хотите разработать компонент «форма с кнопками». В кнопке необходимо наличие иконки.

Простота

Простота достигается тем, что структура «Блок-Элемент» подразумевает наличие только двух уровней вложенности.

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

Изолированность

Как уже было упомянуто, компонент формы решает только свои собственные задачи, не влияя на внутреннее устройство кнопки, но может добавлять ей новое поведение с помощью модификаторов и миксинов, что соответствует принципу открытости/закрытости .

Переиспользуемость

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

Под словами “не знает ничего о форме” я подразумеваю, например, расположение относительно других элементов. То есть не стоит задавать внешние отступы или координаты компоненту, являющемуся блоком, поскольку этот блок может стать элементом любого другого блока, а в разных случаях вам может понадобиться по разному расположить одну и ту же кнопку.

❌ Плохо

Для самой кнопки определена внешняя геометрия (например, margin ), поэтому при использовании её в других компонентах может потребоваться их переопределять:

/** Блок my-button */
export const MyButton = styled.button`
margin: 16px;
`;
/** Блок my-form */
export const MyForm = styled.form``;

✅ Хорошо

Для кнопки по умолчанию не определена внешняя геометрия, определять её будут блоки, элементами которых будет эта кнопка:

/** Блок my-button */
export const MyButton = styled.button``;
/** Блок my-form */
export const MyForm = styled.form`
/** Элемент my-form__button */
${MyButton} {
margin: 16px;
}
`;

Заключение

БЭМ, вопреки распространённому мнению, — не просто способ наименования CSS-классов, а более абстрактная методология, принципы которой применимы для любого технологического стека и не заставляют использовать конкретные инструменты.

Глубокое понимание достаточно простых принципов БЭМ позволяет писать гораздо более поддерживаемый код в любом проекте.