Хотите заказать веб-сайт? Связаться с нами

Emotion в React: гайд по CSS-in-JS стилям

Emotion — одна из самых популярных CSS-in-JS библиотек в экосистеме React. Она позволяет описывать стили прямо в JavaScript или TypeScript коде, объединяя привычный синтаксис CSS с возможностями языка программирования: переменными, функциями, условиями и пропсами компонентов. В этом уроке разберём, зачем нужен Emotion, как его установить и настроить, какие способы стилизации он предлагает, а также сравним библиотеку с другими популярными решениями.

Материал будет полезен как новичкам, которые впервые сталкиваются с подходом CSS-in-JS, так и разработчикам, уже знакомым со styled-components и присматривающимся к альтернативным инструментам стилизации.

Emotion в React: гайд по CSS-in-JS стилям

Что такое Emotion и зачем он нужен

Emotion — это библиотека для стилизации React-компонентов по принципу CSS-in-JS. Вместо отдельных файлов со стилями разработчик описывает CSS прямо в компоненте, получая доступ к переменным JavaScript, состоянию и пропсам. Это удобно, когда внешний вид элемента зависит от данных — например, цвет кнопки меняется в зависимости от статуса заказа или выбранной темы приложения.

Библиотека появилась как более лёгкая и гибкая альтернатива styled-components и быстро завоевала популярность в сообществе. Сегодня Emotion используется не только напрямую в проектах, но и как внутренний движок стилизации в известных UI-библиотеках, включая MUI (Material UI) и Chakra UI.

Среди ключевых преимуществ Emotion можно выделить следующее.

  1. Изолированные стили на уровне компонента без конфликтов имён классов
  2. Динамическая генерация стилей на основе пропсов и состояния компонента
  3. Поддержка серверного рендеринга (SSR) из коробки
  4. Два независимых API стилизации — css prop и styled
  5. Автоматическая расстановка вендорных префиксов и минификация итогового 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

Emotion предлагает разработчику на выбор два основных способа описания стилей — через css prop и через функцию 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

Помимо базовой стилизации, 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-приложений в продакшене и на что обратить внимание при выборе инструмента под конкретный проект.

Теги: