Верстка сайту по методології BEM
BEM (Block, Element, Modifier) — методологія найменування CSS-класів та організації компонентів, розроблена в Яндексі. У великих проектах BEM вирішує конкретну проблему: CSS глобальний, і без системи найменування стилі з однієї частини сайту ломають іншу.
Синтаксис
.block {} /* Блок — незалежний компонент */
.block__element {} /* Елемент — частина блоку, не існує окремо */
.block--modifier {} /* Модифікатор — стан або варіація блоку */
.block__element--mod {} /* Модифікатор елемента */
Подвійне підкреслення — елемент. Подвійне тире — модифікатор. Жодних трьох рівнів вкладеності в класі (block__element__subelement — помилка).
Практичний приклад: карточка товару
<article class="product-card product-card--featured">
<div class="product-card__badge product-card__badge--new">Новинка</div>
<figure class="product-card__media">
<img
class="product-card__image"
src="product.webp"
alt="Назва товару"
width="320"
height="240"
>
</figure>
<div class="product-card__body">
<h2 class="product-card__title">Назва товару</h2>
<p class="product-card__description">Короткий опис...</p>
<div class="product-card__pricing">
<span class="product-card__price product-card__price--current">2 990 ₽</span>
<span class="product-card__price product-card__price--old">4 490 ₽</span>
<span class="product-card__discount">−33%</span>
</div>
</div>
<footer class="product-card__footer">
<button class="btn btn--primary btn--full-width product-card__action">
У кошик
</button>
<button class="wishlist-btn product-card__wishlist" aria-label="В улюблене">
<svg class="wishlist-btn__icon">...</svg>
</button>
</footer>
</article>
CSS:
/* Блок */
.product-card {
display: grid;
grid-template-rows: auto 1fr auto;
border: 1px solid var(--color-border);
border-radius: 8px;
overflow: hidden;
background: var(--color-surface);
transition: box-shadow 200ms ease;
}
.product-card:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
/* Модифікатор блоку */
.product-card--featured {
border-color: var(--color-accent);
}
/* Елементи */
.product-card__media {
position: relative;
aspect-ratio: 4 / 3;
overflow: hidden;
margin: 0;
}
.product-card__image {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 300ms ease;
}
.product-card:hover .product-card__image {
transform: scale(1.05);
}
.product-card__badge {
position: absolute;
top: 12px;
left: 12px;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 600;
}
.product-card__badge--new { background: #22c55e; color: white; }
.product-card__badge--sale { background: #ef4444; color: white; }
.product-card__body {
padding: 16px;
display: flex;
flex-direction: column;
gap: 8px;
}
.product-card__pricing {
display: flex;
align-items: baseline;
gap: 8px;
}
.product-card__price--current {
font-size: 1.25rem;
font-weight: 700;
color: var(--color-text);
}
.product-card__price--old {
font-size: 0.875rem;
color: var(--color-muted);
text-decoration: line-through;
}
.product-card__footer {
padding: 12px 16px;
display: flex;
gap: 8px;
border-top: 1px solid var(--color-border);
}
.product-card__action { flex: 1; }
Структура файлів (File-per-block)
src/
blocks/
product-card/
product-card.html # Шаблон / Storybook
product-card.css # Стилі блоку
product-card.js # JS (опціонально)
btn/
btn.css
wishlist-btn/
wishlist-btn.css
header/
header.css
header.js
Один файл на блок — чітке розграничення. У збірці (Vite, Webpack) імпортуємо тільки потрібні блоки.
Відмінності від CSS Modules та utility-first
| Підхід | Сильні сторони | Слабі сторони |
|---|---|---|
| BEM | Читабельні класи, явна структура, не потребує тулінгу | Багатослівність, ризик "а що це взагалі за елемент" |
| CSS Modules | Автоматична ізоляція, нема конфліктів імен | Потребує сборщик, складніше debug в DevTools |
| Tailwind | Швидкість прототипування, немає найменування | Довгі className, важко читати HTML |
BEM залишається актуальним вибором для:
- Команд без єдиного JS-фреймворку (MPA, CMS-шаблони)
- Проектів, де дизайнери або верстальщики працюють з чистим HTML/CSS
- Стилегайдів та UI-бібліотек, які використовуються в різних контекстах
Типові помилки
Три рівні вкладеності в класі:
<!-- Неправильно -->
<div class="nav__list__item">
<!-- Правильно — item є елементом блоку nav, не list -->
<div class="nav__item">
Модифікатор без базового класу:
<!-- Неправильно -->
<button class="btn--primary">
<!-- Правильно -->
<button class="btn btn--primary">
Контекстні стилі через вкладеність:
/* Неправильно — привязка до контексту, порушує ізольованість */
.sidebar .product-card { font-size: 0.875rem; }
/* Правильно — модифікатор -->
.product-card--compact { font-size: 0.875rem; }
Глобальні стилі станів замість модифікаторів:
/* Неправильно */
.is-active { color: red; }
/* Правильно */
.nav__link--active { color: var(--color-accent); }
Терміни
Верстка по BEM потребує трохи більше часу через продумане найменування, але економить час при підтримці:
| Обсяг | Час |
|---|---|
| Landing page (6–8 блоків) | 1.5–2.5 дні |
| Корпоративний сайт | 4–6 днів |
| UI-кит (20–30 компонентів) | 5–8 днів |







