BEM
BEM (Block-Element-Modifier) — методология именования CSS-классов, которая делает код предсказуемым, масштабируемым и лёгким для поддержки. Разработана в Яндексе.
Зачем нужно
Без системы именования CSS-классы быстро превращаются в хаос: .title, .title2, .big-title, .header-title. BEM даёт чёткие правила: каждый класс говорит, к какому компоненту (блоку) он относится, что он стилизует (элемент) и какой вариант описывает (модификатор).
Где используется
- Крупные проекты с командной разработкой
- Компонентный подход (каждый блок = компонент)
- HTML-вёрстка без CSS-in-JS
- Проекты с длительной поддержкой
- Design-системы
Предпосылки
- Каскад и специфичность — почему BEM избегает вложенности
- Селекторы — CSS-классы
Концепция
Block (Блок)
Самостоятельный компонент, который имеет смысл сам по себе.
/* Блоки */
.card { }
.header { }
.search-form { }
.nav { }
.button { }
Element (Элемент)
Часть блока, которая не имеет смысла вне его контекста. Отделяется двойным подчёркиванием __.
/* Элементы блока .card */
.card__title { }
.card__image { }
.card__body { }
.card__footer { }
/* Элементы блока .search-form */
.search-form__input { }
.search-form__button { }
Modifier (Модификатор)
Вариант или состояние блока/элемента. Отделяется двойным дефисом --.
/* Модификаторы блока */
.card--featured { }
.card--compact { }
.button--primary { }
.button--large { }
/* Модификаторы элемента */
.card__title--highlighted { }
.nav__link--active { }
Примеры
Карточка
<article class="card card--featured">
<img class="card__image" src="photo.jpg" alt="Фото">
<div class="card__body">
<h3 class="card__title">Заголовок</h3>
<p class="card__text">Описание карточки</p>
</div>
<footer class="card__footer">
<button class="button button--primary">Подробнее</button>
</footer>
</article>
.card {
border: 1px solid #dee2e6;
border-radius: 12px;
overflow: hidden;
}
.card--featured {
border-color: #007bff;
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.15);
}
.card__image {
width: 100%;
height: 200px;
object-fit: cover;
}
.card__body {
padding: 16px;
}
.card__title {
font-size: 1.25rem;
margin-bottom: 8px;
}
.card__text {
color: #6c757d;
line-height: 1.6;
}
.card__footer {
padding: 12px 16px;
border-top: 1px solid #dee2e6;
}
Навигация
<nav class="nav">
<a class="nav__link nav__link--active" href="/">Главная</a>
<a class="nav__link" href="/about">О нас</a>
<a class="nav__link" href="/contact">Контакты</a>
</nav>
.nav {
display: flex;
gap: 4px;
background: #f8f9fa;
padding: 4px;
border-radius: 8px;
}
.nav__link {
padding: 8px 16px;
text-decoration: none;
color: #333;
border-radius: 6px;
transition: background 200ms;
}
.nav__link:hover {
background: #e9ecef;
}
.nav__link--active {
background: #007bff;
color: white;
}
Форма
<form class="form form--inline">
<div class="form__group">
<label class="form__label">Email</label>
<input class="form__input form__input--error" type="email">
<span class="form__message form__message--error">Невалидный email</span>
</div>
<button class="form__submit button button--primary">Отправить</button>
</form>
.form { }
.form--inline {
display: flex;
align-items: flex-end;
gap: 16px;
}
.form__group {
display: flex;
flex-direction: column;
gap: 4px;
}
.form__label {
font-size: 0.875rem;
font-weight: 600;
}
.form__input {
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 6px;
}
.form__input--error {
border-color: #dc3545;
}
.form__message--error {
color: #dc3545;
font-size: 0.75rem;
}
Файловая структура
components/
├── card/
│ ├── card.css
│ └── card.html
├── button/
│ └── button.css
├── nav/
│ └── nav.css
└── form/
└── form.css
Правила BEM
- Только классы — никаких id, тегов или вложенных селекторов
- Плоская структура —
.card__title, а не.card .titleи не.card__body__title - Элемент принадлежит блоку — нет
__внутри__:/* ОШИБКА */ .card__body__title { } /* ПРАВИЛЬНО */ .card__title { } - Модификатор не используется без базового класса:
<!-- ОШИБКА --> <div class="card--featured"> <!-- ПРАВИЛЬНО --> <div class="card card--featured"> - Блок не зависит от контекста —
.cardработает одинаково везде
Частые ошибки
- Глубокая вложенность элементов —
card__header__title__icon:/* ОШИБКА — BEM не вкладывает элементы в элементы */ .card__header__title { } /* ПРАВИЛЬНО — элемент всегда от блока */ .card__title { } - Использование тегов вместо классов:
/* ОШИБКА — привязка к HTML-структуре */ .card h3 { } /* ПРАВИЛЬНО */ .card__title { } - Модификатор без базового класса — модификатор только ДОБАВЛЯЕТ/ИЗМЕНЯЕТ стили
- Слишком много модификаторов — если модификаторов больше 3, возможно это отдельный блок
- BEM для утилитарных классов —
.mt-20,.text()-center— это не BEM, это утилиты
Практика
- Создать компонент «карточка» по BEM
- Сделать навигацию с active-модификатором
- Создать форму с модификаторами ошибок
- Организовать файловую структуру по блокам
- Проверить: нет ли вложенных элементов (
__внутри__)
Связанные темы
- CSS Modules — scoped-стили
- Sass — BEM + Sass (удобная вложенность)
- Каскад и специфичность — почему BEM использует плоские селекторы