CSS-in-JS: Styled Components, Emotion
CSS-in-JS — подход к стилизации, при котором CSS пишется прямо в JavaScript-файле и привязывается к компоненту; наиболее популярные библиотеки — Styled Components и Emotion.
Зачем нужно
CSS-in-JS решает проблему глобального пространства имён CSS и позволяет использовать всю мощь JavaScript для динамических стилей: условные правила на основе пропсов, темизация через context, автоматическое удаление неиспользуемых стилей. Библиотеки генерируют уникальные классы в runtime, исключая конфликты. Это особенно удобно для дизайн-систем с полной темизацией.
Где используется
- React-приложения с динамической темизацией (Material UI v5 использует Emotion)
- Дизайн-системы, где стили сильно зависят от пропсов и темы
- Команды, предпочитающие держать стили и логику компонента в одном файле
Styled Components
import styled from 'styled-components';
// Создание стилизованного компонента
const Button = styled.button`
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
/* Динамические стили на основе пропсов */
background: ${({ variant }) =>
variant === 'primary' ? '#0070f3' : 'transparent'};
color: ${({ variant }) =>
variant === 'primary' ? 'white' : '#0070f3'};
border: ${({ variant }) =>
variant === 'primary' ? 'none' : '1px solid #0070f3'};
&:hover {
opacity: 0.8;
}
&:disabled {
opacity: 0.4;
cursor: not-allowed;
}
`;
// Использование
function App() {
return (
<>
<Button variant="primary">Сохранить</Button>
<Button variant="secondary">Отмена</Button>
</>
);
}
Темизация через ThemeProvider
import { ThemeProvider, styled } from 'styled-components';
const theme = {
colors: {
primary: '#0070f3',
background: '#ffffff',
text: '#333333',
},
spacing: {
sm: '8px',
md: '16px',
lg: '24px',
},
};
const Card = styled.div`
background: ${({ theme }) => theme.colors.background};
padding: ${({ theme }) => theme.spacing.md};
color: ${({ theme }) => theme.colors.text()};
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`;
function App() {
return (
<ThemeProvider theme={theme}>
<Card>Содержимое карточки</Card>
</ThemeProvider>
);
}
Emotion — альтернатива
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import styled from '@emotion/styled';
// Вариант 1: css prop
const buttonStyle = css`
padding: 8px 16px;
background: #0070f3;
color: white;
`;
function Button({ children }) {
return <button css={buttonStyle}>{children}</button>;
}
// Вариант 2: styled (идентично Styled Components)
const StyledButton = styled.button`
padding: 8px 16px;
background: #0070f3;
`;
Частые ошибки
- CSS-in-JS в SSR без настройки — без серверного extracta стили вставляются после JS, что вызывает мерцание (FOUC); нужно настроить ServerStyleSheet (styled-components) или cache (emotion).
- Лишние ре-рендеры из-за инлайн-объектов — передача объекта стилей напрямую как пропс создаёт новый объект на каждый рендер.
- Накладные расходы в runtime — CSS-in-JS генерирует стили в JS; для критичных по производительности приложений рассмотрите CSS Modules или zero-runtime решения (Linaria, Vanilla Extract).