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-файлы