CSS-in-JS: обзор подходов

CSS-in-JS — подход к написанию стилей в JavaScript-коде компонентов, обеспечивающий scoping, динамические стили и colocation.

Зачем нужно

CSS-in-JS решает проблему глобального пространства имён CSS: каждый компонент получает изолированные стили без риска конфликтов. Стили могут зависеть от props, state и темы. Популярен в React-экосистеме, хотя тренд в 2024-2025 движется обратно к CSS-файлам из-за производительности.

Где используется

  • React-компоненты с динамическими стилями
  • Дизайн-системы с темизацией через props
  • Проекты где colocation (HTML+JS+CSS в одном файле) важна
  • Next.js / Remix приложения

Основной контент

Styled Components

import styled from 'styled-components';

const Button = styled.button`
  background: ${props => props.primary ? '#0070f3' : 'white'};
  color: ${props => props.primary ? 'white' : '#0070f3'};
  padding: 8px 16px;
  border-radius: 4px;
  border: 1px solid #0070f3;
  cursor: pointer;

  &:hover {
    opacity: 0.8;
  }
`;

// Использование
<Button primary>Primary</Button>
<Button>Secondary</Button>

Emotion

import { css } from '@emotion/react';

const buttonStyle = css`
  background: #0070f3;
  color: white;
  padding: 8px 16px;
`;

// Объектный синтаксис
const buttonObj = css({
  background: '#0070f3',
  color: 'white',
  padding: '8px 16px',
  '&:hover': {
    opacity: 0.8,
  },
});

function Button({ children }) {
  return <button css={buttonStyle}>{children}</button>;
}

CSS Modules (не CSS-in-JS, но похоже)

/* Button.module.css */
.button {
  background: #0070f3;
  color: white;
  padding: 8px 16px;
}

.primary {
  background: #005ce0;
}
import styles from './Button.module.css';

function Button({ primary }) {
  return (
    <button className={`${styles.button} ${primary ? styles.primary : ''}`}>
      Click
    </button>
  );
}

Сравнение подходов

Подход Scoping Динамика Производительность Популярность
CSS Modules Да Нет Отличная Высокая
Styled Components Да Да Средняя (runtime) Высокая
Emotion Да Да Средняя (runtime) Высокая
Tailwind CSS Нет (утилиты) Через классы Отличная Очень высокая
Vanilla Extract Да Нет (compile-time) Отличная Растёт

Тренды 2024-2025

Из-за проблем с производительностью (серверный рендеринг + hydration) runtime CSS-in-JS библиотеки (Styled Components, Emotion) теряют популярность. Тренд: compile-time решения (Vanilla Extract, Linaria) и CSS Modules + CSS Custom Properties.

Частые ошибки

  • Runtime CSS-in-JS в Server Components — Styled Components и Emotion не поддерживают React Server Components без специальных обходных решений
  • Переусложнение простых компонентов — для простого статичного компонента CSS Modules или обычный CSS класс проще
  • Потеря производительности — runtime CSS-in-JS генерирует стили на клиенте; это медленнее, чем статические CSS-файлы

Связанные темы

Ресурсы