Sass, CSS Modules или CSS-in-JS: как стилизовать приложение
Практика3 минРедакция Innovialabs
Коротко
Sass — препроцессор для удобного написания CSS, CSS Modules изолируют классы на уровне файла, а CSS-in-JS описывает стили в JavaScript. Для большинства React-приложений с SSR надёжный выбор — CSS Modules (при желании вместе с Sass) или CSS-in-JS без runtime.
Коротко о каждом подходе
- Sass (SCSS) — препроцессор. Добавляет переменные, вложенность, миксины и функции, на выходе получается обычный CSS. Сам по себе не изолирует стили: классы остаются глобальными.
- CSS Modules — обычные
.cssили.scssфайлы, в которых сборщик делает имена классов уникальными. Стили изолированы на уровне файла, а результат — статический CSS. - CSS-in-JS — стили описываются в JavaScript рядом с компонентом. Есть две ветки: runtime (стили генерируются в браузере при рендере) и zero-runtime (стили извлекаются в CSS-файлы при сборке).
Эти подходы можно сочетать: Sass часто используют внутри CSS Modules.
Сравнение по главным критериям
| Критерий | Sass (глобально) | CSS Modules | CSS-in-JS runtime | CSS-in-JS zero-runtime |
|---|---|---|---|---|
| Изоляция | вручную, через БЭМ | автоматически | автоматически | автоматически |
| Работа в браузере | только CSS | только CSS | JS генерирует стили | только CSS |
| Динамика от props | через классы и CSS-переменные | через классы и CSS-переменные | напрямую | ограниченно, через переменные |
| SSR и серверные компоненты | без проблем | без проблем | нужна настройка, есть ограничения | обычно без проблем |
| Типизация | нет | можно сгенерировать | есть | есть |
| Порог входа | низкий | низкий | средний | средний |
Изоляция стилей
Главная проблема большого CSS — конфликты имён: класс .title из одного компонента ломает другой. Варианты решения:
- Sass + методология БЭМ: договорённость об именах
.card__title--active. Работает, но держится на дисциплине команды. - CSS Modules:
styles.titleпревращается в уникальное имя автоматически. Конфликты исключены без договорённостей. - CSS-in-JS: стили привязаны к компоненту, глобальные правила выносятся явно.
Производительность
- Статический CSS (Sass, CSS Modules, zero-runtime) загружается и кэшируется браузером отдельно от JS и не требует вычислений при рендере.
- Runtime CSS-in-JS увеличивает размер JS-бандла и выполняет работу при каждом рендере: сериализует стили и вставляет их в документ. На простых страницах это незаметно, на сложных интерфейсах с частыми перерисовками может ощущаться.
Если важны скорость загрузки и Core Web Vitals, предпочтительнее подходы, которые отдают готовый CSS.
SSR и серверные компоненты
В современных React-фреймворках с серверным рендерингом и серверными компонентами runtime CSS-in-JS требует дополнительной настройки для сбора стилей на сервере, а в серверных компонентах такие библиотеки, как правило, не работают. Проверяйте документацию фреймворка и библиотеки перед выбором. CSS Modules и Sass поддерживаются большинством фреймворков из коробки.
Удобство разработки (DX)
- Sass привычен большинству верстальщиков, но глобальное пространство имён требует аккуратности.
- CSS Modules — тот же CSS, просто импортируемый как объект. Минус: динамические стили приходится делать через комбинации классов или CSS-переменные.
- CSS-in-JS удобен, когда стили сильно зависят от состояния и props, и хорошо типизируется с TypeScript. Минус — смешение логики и стилей в одном файле, что нравится не всем.
Матрица выбора
| Тип проекта | Рекомендация |
|---|---|
| Лендинг или многостраничный сайт без фреймворка | Sass + БЭМ |
| React/Next.js-приложение с SSR | CSS Modules (можно с Sass) или zero-runtime CSS-in-JS |
| SPA без SSR с богатой динамикой темы | CSS-in-JS, runtime допустим |
| Дизайн-система для нескольких продуктов | zero-runtime CSS-in-JS или CSS Modules + CSS-переменные для токенов |
| Легаси-проект на глобальном CSS | постепенный переход на CSS Modules по компонентам |
Отдельный вариант — utility-first фреймворки вроде Tailwind CSS: это другой подход, который решает изоляцию за счёт отказа от собственных классов.
Частые ошибки
- Смешивать три подхода в одном проекте без правил — стили становится трудно искать.
- Вычислять в runtime то, что можно описать CSS-переменной: цвет темы, отступы, размеры.
- Не выносить токены (цвета, шрифты, отступы) в одно место — при любом подходе они должны жить централизованно.