Практика: переводим компонент на БЭМ
Соберём всё, что было в главе, на одном примере. Рефакторинг — изменение кода без изменения его поведения: страница выглядит так же, но код становится понятнее. Возьмём карточку товара, которую писали «как получится», и переведём её на БЭМ.
Исходный код
Вот карточка в том виде, в каком она часто встречается в старых проектах:
<style>
#catalog div { padding: 12px; border: 1px solid silver; border-radius: 8px; max-width: 240px; margin-bottom: 8px; }
#catalog div h3 { margin: 0 0 6px; font-size: 18px; }
#catalog div span { color: seagreen; font-weight: bold; }
#catalog div button { margin-top: 8px; padding: 6px 12px; border: none; border-radius: 6px; background: seagreen; color: white; }
.sale { border-color: crimson !important; }
.sale span { color: crimson; }
</style>
<section id="catalog">
<div>
<h3>Рюкзак</h3>
<span>40 €</span><br>
<button>Купить</button>
</div>
<div class="sale">
<h3>Палатка</h3>
<span>72 €</span><br>
<button>Купить</button>
</div>
</section>Обратите внимание: у второй карточки рамка красная, а цена осталась зелёной — правило .sale span проиграло селектору с id.
Что здесь не так
- Селекторы завязаны на id
catalog: вне каталога карточку не показать. - Стили привязаны к тегам: замените
<h3>на<h2>— оформление пропадёт. #catalog divзадевает любой<div>, который появится внутри карточки.- Модификатор держится на
!important, и всё равно перекрасил не всё.
Шаг 1: находим блоки
Сначала решаем, какие части самостоятельны. Карточка — блок product. Кнопка встречается по всему сайту — отдельный блок button. Её место в карточке задаст элемент через микс.
Шаг 2: элементы и модификаторы
| Было | Стало | Что это |
|---|---|---|
#catalog div | .product | блок |
#catalog div h3 | .product__title | элемент |
#catalog div span | .product__price | элемент |
#catalog div button | .button и .product__buy | блок и элемент (микс) |
.sale | .product--sale | модификатор |
<br> больше не нужен: цене достаточно display: block.
Результат
<style>
.button { padding: 6px 12px; border: none; border-radius: 6px; background: seagreen; color: white; }
.product { padding: 12px; border: 1px solid silver; border-radius: 8px; max-width: 240px; margin-bottom: 8px; }
.product--sale { border-color: crimson; }
.product__title { margin: 0 0 6px; font-size: 18px; }
.product__price { display: block; color: seagreen; font-weight: bold; }
.product--sale .product__price { color: crimson; }
.product__buy { margin-top: 8px; }
</style>
<section>
<div class="product">
<h3 class="product__title">Рюкзак</h3>
<span class="product__price">40 €</span>
<button class="button product__buy">Купить</button>
</div>
<div class="product product--sale">
<h3 class="product__title">Палатка</h3>
<span class="product__price">72 €</span>
<button class="button product__buy">Купить</button>
</div>
</section>Карточки выглядят как раньше, но теперь цена в акционной карточке действительно красная. В коде нет ни id, ни !important, а карточку можно поставить в любое место сайта.
Частая ошибка
Переименовать классы, но оставить вложенные селекторы:
.catalog .product .product__title { margin: 0 0 6px; }
.catalog .product .product__price { color: seagreen; }Имена стали «бэмными», а специфичность осталась высокой, и карточка по-прежнему работает только внутри .catalog. Проверяйте результат рефакторинга: почти каждый селектор должен состоять из одного класса.