Emotion в React: гайд по CSS-in-JS стилям
Emotion — одна из самых популярных CSS-in-JS библиотек в экосистеме React. Она позволяет описывать стили прямо в JavaScript или TypeScript коде, объединяя привычный синтаксис CSS с возможностями языка программирования: переменными, функциями, условиями и пропсами компонентов. В этом уроке разберём, зачем нужен Emotion, как его установить и настроить, какие способы стилизации он предлагает, а также сравним библиотеку с другими популярными решениями.
Материал будет полезен как новичкам, которые впервые сталкиваются с подходом CSS-in-JS, так и разработчикам, уже знакомым со styled-components и присматривающимся к альтернативным инструментам стилизации.
Что такое Emotion и зачем он нужен
Библиотека появилась как более лёгкая и гибкая альтернатива styled-components и быстро завоевала популярность в сообществе. Сегодня Emotion используется не только напрямую в проектах, но и как внутренний движок стилизации в известных UI-библиотеках, включая MUI (Material UI) и Chakra UI.
Среди ключевых преимуществ Emotion можно выделить следующее.
- Изолированные стили на уровне компонента без конфликтов имён классов
- Динамическая генерация стилей на основе пропсов и состояния компонента
- Поддержка серверного рендеринга (SSR) из коробки
- Два независимых API стилизации —
cssprop иstyled - Автоматическая расстановка вендорных префиксов и минификация итогового CSS
Установка и настройка Emotion в проекте React
Для работы с Emotion потребуется установить два пакета: @emotion/react отвечает за основной рантайм и функцию css, а @emotion/styled добавляет API для создания стилизованных компонентов, похожий на styled-components.
npm install @emotion/react @emotion/styled
Чтобы использовать css prop без дополнительного импорта в каждом файле, сборщик нужно настроить на автоматическую JSX-трансформацию с указанием jsxImportSource. Например, для проекта на Vite достаточно передать соответствующую опцию в плагин React.
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react({ jsxImportSource: '@emotion/react' })],
});
После такой настройки можно писать css={...} прямо в JSX-разметке без ручного добавления служебного комментария /** @jsxImportSource @emotion/react */ в начале каждого файла.
Способы стилизации css prop и styled API
styled. Рассмотрим каждый из них подробнее.css prop
css prop позволяет передать стили прямо в JSX-элемент через специальный атрибут css. Значением может быть как объект стилей, так и результат вызова функции css с шаблонной строкой.
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
const buttonStyle = css`
background-color: #326ec1;
color: white;
padding: 8px 16px;
border-radius: 6px;
&:hover {
background-color: #ffb131;
}
`;
function SubmitButton() {
return <button css={buttonStyle}>Отправить</button>;
}
styled API
Функция styled создаёт новый React-компонент с уже привязанными стилями. Такой подход удобен, когда нужно переиспользовать один и тот же визуальный блок в разных местах приложения, а стили должны реагировать на пропсы.
import styled from '@emotion/styled';
interface CardProps {
isActive: boolean;
}
const Card = styled.div<CardProps>`
padding: 16px;
border-radius: 8px;
background-color: ${(props) => (props.isActive ? '#326ec1' : '#ffffff')};
color: ${(props) => (props.isActive ? '#ffffff' : '#000000')};
`;
function Feature({ isActive }: CardProps) {
return <Card isActive={isActive}>Контент карточки</Card>;
}
Если проект написан на TypeScript, старайтесь чаще использовать объектный синтаксис стилей вместо шаблонных строк — редактор кода будет подсказывать корректные CSS-свойства и подсвечивать опечатки ещё на этапе написания кода.
Продвинутые возможности Emotion
Композиция стилей
Функция css позволяет комбинировать несколько наборов стилей в массиве. Стили применяются по порядку, и более поздние переопределяют совпадающие свойства более ранних — это удобно для создания базового набора стилей с вариациями.
const baseStyle = css`
padding: 12px 20px;
border-radius: 6px;
`;
const primaryStyle = css`
background-color: #326ec1;
color: white;
`;
function PrimaryButton() {
return <button css={[baseStyle, primaryStyle]}>Купить</button>;
}
Тема и ThemeProvider
Компонент ThemeProvider из @emotion/react позволяет передать объект темы через контекст всем дочерним компонентам. Получить доступ к теме внутри компонента можно с помощью хука useTheme.
import { ThemeProvider, useTheme } from '@emotion/react';
const theme = {
colors: {
primary: '#326ec1',
accent: '#ffb131',
},
};
function App() {
return (
<ThemeProvider theme={theme}>
<ThemedButton />
</ThemeProvider>
);
}
function ThemedButton() {
const theme = useTheme();
return <button css={{ background: theme.colors.primary }}>Кнопка</button>;
}
Keyframes и анимации
Для описания CSS-анимаций Emotion предоставляет функцию keyframes. Она возвращает уникальное имя анимации, которое затем можно подставить в свойство animation внутри обычного вызова css.
import { keyframes, css } from '@emotion/react';
const fadeIn = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`;
const animatedBlock = css`
animation: ${fadeIn} 0.4s ease-in;
`;
Emotion в сравнении с другими решениями
Прежде чем выбирать инструмент для стилизации нового проекта, полезно сравнить Emotion с другими популярными подходами.
| Инструмент | Особенности |
|---|---|
| Emotion | Гибкий CSS-in-JS с двумя API (css и styled), поддержка тем и SSR, небольшой размер рантайма |
| Styled Components | Похожий подход через теговые шаблонные строки, чуть больший размер бандла, богатая экосистема |
| Tailwind CSS | Утилитарные классы прямо в разметке, отсутствие рантайма, но менее удобная динамика на основе пропсов |
| CSS Modules | Изоляция классов на уровне сборщика без рантайма, но без прямого доступа к JS-логике внутри стилей |
Если проекту важна гибкая работа с темами, динамические стили на основе пропсов и совместимость с готовыми UI-китами вроде MUI, Emotion — один из самых удобных вариантов. Для небольших статичных интерфейсов без сложной логики стоит присмотреться к более лёгким по рантайму решениям вроде Tailwind CSS или CSS Modules. В крупных командных проектах выбор часто определяется не только техническими характеристиками, но и тем, какой подход уже принят в команде и насколько легко будет обучить новых участников.
Не создавайте объект стилей заново при каждом рендере компонента, если он не зависит от пропсов или состояния, — выносите такие стили за пределы компонента или оборачивайте вычисление в useMemo, чтобы снизить нагрузку на движок Emotion в больших приложениях.
Итоги
Emotion — гибкая и производительная библиотека для стилизации React-приложений, которая поддерживает как декларативный css prop, так и знакомый по styled-components API styled. Мы разобрали установку и настройку библиотеки, базовые и продвинутые возможности, включая композицию стилей, работу с темами и анимации, а также сравнили Emotion с альтернативными подходами к стилизации.
В следующем уроке поговорим о том, как оптимизировать производительность стилизации React-приложений в продакшене и на что обратить внимание при выборе инструмента под конкретный проект.