CSS модули

CSS модули — это современный способ организации стилей в приложениях на React, обеспечивающий изоляцию стилей и предотвращение конфликтов имен классов. В сочетании с React Aria, библиотекой для создания доступных пользовательских интерфейсов, CSS модули позволяют создавать компоненты, полностью соответствующие стандартам доступности, с аккуратной структурой стилей.


Подключение CSS модулей

В React проекте, созданном через Create React App или аналогичный билд-инструмент, CSS модули подключаются следующим образом:

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

function Button({ children }) {
  return <button className={styles.button}>{children}</button>;
}

Особенности подключения:

  • Файл должен иметь расширение .module.css.
  • Классы автоматически локализуются, что предотвращает глобальные конфликты.
  • Можно комбинировать локальные и глобальные классы через шаблонные строки или библиотеку clsx.
import clsx from 'clsx';
import styles from './Button.module.css';

function Button({ primary }) {
  return (
    <button className={clsx(styles.button, primary && styles.primary)}>
      Кнопка
    </button>
  );
}

Интеграция с React Aria

React Aria предоставляет набор хуков и компонентов для управления состоянием и поведением элементов с поддержкой доступности (ARIA). CSS модули позволяют стилизовать эти элементы без риска переписывания глобальных стилей.

Пример кнопки с использованием хуков React Aria и CSS модулей:

import { useButton } from '@react-aria/button';
import { useRef } from 'react';
import styles from './Button.module.css';

function AriaButton({ children, onPress }) {
  const ref = useRef();
  const { buttonProps } = useButton({ onPress }, ref);

  return (
    <button {...buttonProps} ref={ref} className={styles.button}>
      {children}
    </button>
  );
}

Ключевые моменты:

  • Хук useButton добавляет ARIA-атрибуты и обработчики событий.
  • CSS модуль отвечает только за визуальное оформление, не вмешиваясь в логику доступности.
  • Стили можно менять без риска сломать ARIA-поддержку.

Работа с динамическими состояниями

React Aria часто требует управления состояниями компонентов: активный, выбранный, фокусированный. CSS модули отлично сочетаются с этим через динамическое присвоение классов:

import { useToggleButton } from '@react-aria/button';
import { useRef, useState } from 'react';
import styles from './ToggleButton.module.css';
import clsx from 'clsx';

function ToggleButton({ children }) {
  const ref = useRef();
  const [isSelected, setSelected] = useState(false);
  const { buttonProps } = useToggleButton(
    {
      isSelected,
      onChange: setSelected
    },
    ref
  );

  return (
    <button
      {...buttonProps}
      ref={ref}
      className={clsx(styles.button, isSelected && styles.selected)}
    >
      {children}
    </button>
  );
}

Особенности:

  • clsx упрощает условное применение стилей.
  • Локальные CSS классы позволяют явно разграничивать состояния без глобального влияния на проект.

Организация стилей для комплексных компонентов

При работе с компонентами, содержащими несколько элементов (например, меню, модальные окна, вкладки), CSS модули позволяют структурировать стили по иерархии, избегая конфликтов:

/* Menu.module.css */
.menu {
  background: white;
  border: 1px solid #ccc;
}

.menuItem {
  padding: 8px 16px;
}

.menuItemSelected {
  background: #0078d4;
  color: white;
}
import { useMenu, useMenuItem } from '@react-aria/menu';
import { useRef } from 'react';
import styles from './Menu.module.css';
import clsx from 'clsx';

function Menu({ items }) {
  const ref = useRef();
  const { menuProps } = useMenu({}, ref);

  return (
    <ul {...menuProps} ref={ref} className={styles.menu}>
      {items.map((item) => (
        <MenuItem key={item.key} item={item} />
      ))}
    </ul>
  );
}

function MenuItem({ item }) {
  const ref = useRef();
  const { menuItemProps, isSelected } = useMenuItem(
    { key: item.key },
    ref
  );

  return (
    <li
      {...menuItemProps}
      ref={ref}
      className={clsx(styles.menuItem, isSelected && styles.menuItemSelected)}
    >
      {item.name}
    </li>
  );
}

Преимущества такого подхода:

  • Полная изоляция стилей элементов меню.
  • Удобное управление состояниями выбранного элемента.
  • Легко масштабировать при добавлении новых компонентов и элементов.

Работа с темизацией и CSS переменными

CSS модули можно сочетать с переменными CSS для создания темной и светлой темы:

/* Button.module.css */
:root {
  --button-bg: #f0f0f0;
  --button-color: #000;
}

.button {
  background-color: var(--button-bg);
  color: var(--button-color);
  border: none;
  padding: 10px 16px;
  cursor: pointer;
  transition: background 0.3s;
}

.button:hover {
  background-color: #e0e0e0;
}

Для темизации можно динамически изменять корневые переменные через JavaScript или React Context, при этом стили компонентов остаются полностью локализованными.


Комбинирование с Tailwind и другими библиотеками

CSS модули не мешают использовать утилитарные библиотеки вроде Tailwind. Можно применять Tailwind классы вместе с локальными:

<button className={`${styles.button} bg-blue-500 hover:bg-blue-600`}>
  Комбинированная кнопка
</button>

Такой подход позволяет гибко управлять дизайном, оставляя CSS модули для локальных и уникальных стилей, а Tailwind — для быстрых утилитарных правок.


Вывод

Использование CSS модулей в сочетании с React Aria обеспечивает изолированную, масштабируемую систему стилей, которая полностью совместима с ARIA-стандартами доступности. Комбинация локальных классов, динамических состояний и переменных CSS делает разработку компонентов более управляемой и безопасной для больших приложений.

CSS модули позволяют создавать чистую архитектуру UI без глобальных конфликтов, а React Aria обеспечивает функциональность и доступность, создавая единый подход к построению сложных и доступных интерфейсов.