← Назад к вопросам

В чем разница между использованием BEM и Scoped-стилей?

2.0 Middle🔥 131 комментариев
#Другое

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

BEM vs Scoped-стили: разница и когда использовать

Оба подхода решают одну проблему: как избежать конфликтов CSS-селекторов в больших приложениях. Но они идут разными путями.

BEM (Block, Element, Modifier)

BEM — это методология назначения классов CSS. Основана на соглашении об именовании.

Структура BEM

<!-- BLOCK -->
<div class="card">
  <!-- ELEMENT -->
  <div class="card__header">
    <h2 class="card__title">Title</h2>
    <!-- MODIFIER -->
    <button class="card__button card__button--primary">Action</button>
  </div>
  
  <!-- ELEMENT -->
  <div class="card__body">
    <p class="card__text">Content</p>
  </div>
  
  <!-- ELEMENT с MODIFIER -->
  <footer class="card__footer card__footer--dark">
    Footer
  </footer>
</div>

Соглашение:

  • Block: card (независимый компонент)
  • Element: card__header (часть блока, существует только в блоке)
  • Modifier: card__button--primary (вариация блока/элемента)

CSS для BEM

/* Block */
.card {
  background: white;
  border: 1px solid #ccc;
  padding: 20px;
}

/* Element */
.card__header {
  border-bottom: 1px solid #eee;
  margin-bottom: 15px;
}

.card__title {
  font-size: 24px;
  margin: 0;
}

.card__button {
  padding: 8px 16px;
  border: none;
  cursor: pointer;
}

/* Modifier */
.card__button--primary {
  background: blue;
  color: white;
}

.card__button--secondary {
  background: gray;
  color: white;
}

.card__footer--dark {
  background: #333;
  color: white;
}

Плюсы BEM

Предсказуемый — видишь HTML, знаешь какие CSS классы ✅ Нет вложенности — селекторы простые ✅ Легко масштабировать — новые варианты просто добавляются ✅ Работает везде — обычный CSS, не нужны инструменты ✅ Specificity контролируем — почти все селекторы одного уровня

Минусы BEM

Многословно — названия длинные ❌ Дублирование — нужно тщательно выбирать имена ❌ Требует дисциплины — команда должна следовать соглашению ❌ Нет encapsulation — стили глобальные

Scoped-стили (CSS Modules, BEM в JS фреймворках)

Scoped-стили — это инкапсуляция CSS внутри компонента. Стили автоматически "скопированы" на компонент.

Пример с CSS Modules (React)

// Card.module.css
.card {
  background: white;
  border: 1px solid #ccc;
  padding: 20px;
}

.header {
  border-bottom: 1px solid #eee;
  margin-bottom: 15px;
}

.title {
  font-size: 24px;
  margin: 0;
}

.button {
  padding: 8px 16px;
  border: none;
  cursor: pointer;
}

.buttonPrimary {
  background: blue;
  color: white;
}

.footer {
  background: #333;
  color: white;
}
// Card.tsx
import styles from './Card.module.css';

function Card() {
  return (
    <div className={styles.card}>
      <div className={styles.header}>
        <h2 className={styles.title}>Title</h2>
        <button className={`${styles.button} ${styles.buttonPrimary}`}>
          Action
        </button>
      </div>
      <footer className={styles.footer}>
        Footer
      </footer>
    </div>
  );
}

Во время сборки CSS Modules трансформирует это в уникальные классы:

<div class="Card_card__x1y2z">
  <div class="Card_header__a9b8c">
    <h2 class="Card_title__m3n4o">Title</h2>
    <button class="Card_button__p5q6r Card_buttonPrimary__s7t8u">
      Action
    </button>
  </div>
  <footer class="Card_footer__v9w0x">
    Footer
  </footer>
</div>

Пример с Styled Components (React)

import styled from 'styled-components';

const CardContainer = styled.div`
  background: white;
  border: 1px solid #ccc;
  padding: 20px;
`;

const Header = styled.div`
  border-bottom: 1px solid #eee;
  margin-bottom: 15px;
`;

const Title = styled.h2`
  font-size: 24px;
  margin: 0;
`;

const Button = styled.button`
  padding: 8px 16px;
  border: none;
  cursor: pointer;
  
  ${props => props.primary && `
    background: blue;
    color: white;
  `}
`;

function Card() {
  return (
    <CardContainer>
      <Header>
        <Title>Title</Title>
        <Button primary>Action</Button>
      </Header>
    </CardContainer>
  );
}

Пример с Vue Scoped Styles

<template>
  <div class="card">
    <div class="header">
      <h2 class="title">Title</h2>
      <button class="button" :class="{ 'button--primary': isPrimary }">
        Action
      </button>
    </div>
    <footer class="footer">Footer</footer>
  </div>
</template>

<style scoped>
.card {
  background: white;
  border: 1px solid #ccc;
  padding: 20px;
}

.header {
  border-bottom: 1px solid #eee;
  margin-bottom: 15px;
}

.title {
  font-size: 24px;
  margin: 0;
}

.button {
  padding: 8px 16px;
  border: none;
  cursor: pointer;
}

.button--primary {
  background: blue;
  color: white;
}

.footer {
  background: #333;
  color: white;
}
</style>

Плюсы Scoped-стилей

Инкапсуляция — стили не попадут в другие компоненты ✅ Простые имена — не нужны длинные BEM имена ✅ Компонент-ориентированный — CSS с JS рядом ✅ Automatic uniqueness — нет конфликтов имён ✅ Легче удалить — удалил компонент, удалились стили

Минусы Scoped-стилей

Требуется build step — не работает с простым CSS ❌ Сложнее делиться стилями — между компонентами ❌ Больше JS — Styled Components добавляют runtime ❌ Harder to debug — сгенерированные селекторы в DevTools ❌ Performance — JS-in-CSS может быть медленнее

Сравнительная таблица

АспектBEMScoped-стили
EncapsulationРучная (соглашение)Автоматическая
Имена классовДлинные, соглашениеКороткие, генерируются
Build требуетсяНетДа (обычно)
Глобальное состояниеДаНет
Шаринг стилейЛегкоСложнее
DevToolsЧитаемоШифровано
PerformanceЛучшеМожет быть медленнее
Learning curveНизкаяСредняя
Для больших проектовНужна дисциплинаВстроено

Когда использовать BEM

✅ Статические сайты (Jekyll, Hugo)
✅ Простые приложения без build-step
✅ Когда CSS важен для SEO
✅ Когда нужна максимальная производительность
✅ Старые браузеры (IE11)

Когда использовать Scoped-стили

✅ React/Vue/Angular приложения
✅ Design systems и component libraries
✅ Большие приложения (100+ компонентов)
✅ Когда важна maintenance
✅ Когда пишешь TypeScript/JS код

Гибридный подход

Много проектов комбинируют оба подхода:

// Глобальные стили (BEM)
// base.css, typography.css, colors.css
// Shared переменные, utilities

// Компонент-специфичные (Scoped)
// Card.module.css
// Button.module.css

Это даёт лучшее из обоих миров:

  • Scoped для инкапсуляции компонентов
  • BEM для shared utilities и базовых стилей

Modern CSS: Tailwind CSS

Отдельная категория, которая находится между BEM и Scoped:

<!-- Tailwind: utility-first -->
<div class="bg-white border border-gray-300 p-5">
  <div class="border-b border-gray-200 mb-4">
    <h2 class="text-2xl font-semibold">Title</h2>
    <button class="px-4 py-2 bg-blue-500 text-white">
      Action
    </button>
  </div>
  <footer class="bg-gray-800 text-white">
    Footer
  </footer>
</div>

Плюсы: быстро писать, нет CSS файлов
Минусы: HTML загромождается, меньше переиспользования

Вывод

BEM — это методология, которая работает везде. Требует дисциплины, но даёт полный контроль.

Scoped-стили — это встроенная инкапсуляция в JavaScript фреймворки. Проще в поддержке больших приложений.

Выбор зависит от:

  • Стека технологий (React vs vanilla HTML)
  • Размера проекта (маленький vs большой)
  • Требования к производительности
  • Опыт команды

В 2025 году для современных web приложений (React, Vue, Angular) я выбираю Scoped-стили. Для статических сайтов и когда нет build-step'а — BEM.