CSS Modules

CSS Modules — это метод организации стилей в проектах на JavaScript, позволяющий избежать глобального конфликта имён классов. Каждый CSS-файл становится локальным по умолчанию, что обеспечивает изоляцию стилей на уровне компонента. При импорте CSS-файла создаётся объект, где ключи — это локальные имена классов, а значения — сгенерированные уникальные идентификаторы.

import styles from './Button.module.css';

function Button() {
  return <button className={styles.primary}>Нажать</button>;
}

В примере styles.primary ссылается на уникальный идентификатор, который генерируется системой сборки (например, Webpack). Это гарантирует отсутствие пересечений с другими классами primary в проекте.


Структура и синтаксис

Файл с CSS Modules обычно имеет расширение .module.css. Поддерживаются все стандартные CSS-свойства, а также вложенные селекторы через синтаксис SCSS-подобных препроцессоров, если используется соответствующий загрузчик.

/* Button.module.css */
.primary {
  background-color: #0070f3;
  color: white;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
}

.primary:hover {
  background-color: #005bb5;
}

Импортированный объект styles автоматически содержит свойства, соответствующие классам .primary и .primary:hover преобразуется в уникальный селектор.


Локальные и глобальные классы

По умолчанию все классы считаются локальными. Для объявления глобального класса используется :global():

:global(.reset) {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

Глобальные классы применяются ко всему проекту и не генерируют уникальные идентификаторы.


Композиция классов

CSS Modules поддерживает композицию классов с помощью ключевого слова composes. Это позволяет создавать новые классы на основе существующих:

/* styles.module.css */
.button {
  padding: 10px 15px;
  border-radius: 5px;
}

.primary {
  composes: button;
  background-color: #0070f3;
  color: white;
}

В результате .primary наследует все свойства .button и добавляет свои собственные.


Динамическое применение классов

В JavaScript возможно динамически комбинировать классы, используя библиотеку clsx или стандартную конкатенацию строк:

import styles from './Button.module.css';
import clsx from 'clsx';

function Button({ isPrimary, isDisabled }) {
  const buttonClass = clsx({
    [styles.primary]: isPrimary,
    [styles.disabled]: isDisabled
  });

  return <button className={buttonClass}>Кнопка</button>;
}

Такой подход упрощает управление состояниями компонента через стили.


Интеграция с MDX

MDX позволяет включать JSX внутри Markdown. С CSS Modules это позволяет связывать стили с компонентами прямо в контенте:

import styles from './Note.module.css';

export const Note = ({ children }) => (
  <div className={styles.note}>{children}</div>
);

В MDX-файле:

<Note>
  Важная информация отображается с применением локальных стилей.
</Note>

Каждый компонент в MDX сохраняет свои стили локальными, что предотвращает конфликты с другими элементами документа.


Организация проекта

Рекомендуется держать CSS Modules рядом с компонентами, чтобы структура была логичной:

/components
  /Button
    Button.jsx
    Button.module.css
  /Note
    Note.jsx
    Note.module.css

Такое расположение облегчает сопровождение и повторное использование компонентов с их стилями.


Преимущества

  • Локальность стилей — отсутствие глобальных конфликтов.
  • Явная связь стилей и компонентов.
  • Поддержка композиции и переиспользования.
  • Совместимость с MDX и современными сборщиками.

Ограничения и рекомендации

  • Не использовать CSS Modules для глобальных тем и базовых сбросов стилей, для этого лучше применять обычные глобальные CSS или CSS-in-JS.
  • Для динамических тем можно комбинировать CSS Modules с библиотеками типа clsx или classnames.
  • Вложенные селекторы должны быть минимальными, чтобы сохранить читабельность и предсказуемость генерации классов.

CSS Modules создают безопасную, изолированную среду для работы со стилями в современных приложениях на JavaScript и MDX, обеспечивая строгую организацию, повторное использование компонентов и гибкость при динамическом управлении классами.