Мой ТОП-5 лучших CSS-in-JS решений

от автора

Привет, Хабр!

В одном из проектов мне нужно было создать сложную админку для крупного клиента. Интерфейс требовал большо количества интерактивностей, а также поддержку различных тем и динамических стилей. Именно тогда я решил обратить свой взгляд на CSS‑in‑JS библиотеки, и это для меня стало большим открытием.

Ведь стилизация компонентов — основа для создания интуитивно понятных и эстетически приятных интерфейсов. И иногда традиционные методы стилизации, такие как CSS‑файлы или препроцессоры, имеют свои ограничения и могут усложнять сам процесс разработки, чего мы точно не хотим.

Здесь вот и приходят на помощь решения CSS‑in‑JS, объединяющие фичи JS и CSS.

CSS‑in‑JS — это подход к стилизации, который позволяет писать стили прямо в JavaScript‑коде. Преимущества такого подхода:

  1. Изоляция стилей: компоненты получают свои собственные стили.

  2. Динамические стили: легко применять стили в зависимости от состояния компонента или пропсов.

  3. Поддержка тем: удобное управление темами и их переключение на лету.

  4. Интеграция с JavaScript.

В этой статье я хотел бы представить свой ТОП-5 лучших решений CSS‑in‑JS, которые я использовал.

Styled Components

Styled Components — это библиотека для стилизации React-компонентов с использованием ES6 и шаблонных литералов. Она позволяет писать CSS в JavaScript, создавая стилизованные компоненты, которые инкапсулируют свои стили. Так стилизация становится более модульной и управляемой.

Styled Components использует теги шаблонных литералов для написания CSS внутри самого JS.

Для начала установим библиотеку с помощью npm или yarn:

npm install styled-components # или yarn add styled-components

После установки можно импортировать библиотеку.

Пример базового использования:

import styled from 'styled-components';  const Button = styled.button`   background-color: #007bff;   color: white;   border: none;   padding: 10px 20px;   border-radius: 4px;   cursor: pointer;    &:hover {     background-color: #0056b3;   } `;  function App() {   return (     <div>       <h1>Welcome to Styled-Components!</h1>       <Button>Click me</Button>     </div>   ); }  export default App;

Создали компонент Button, который можно использовать как обычный React-компонент с предопределенными стилями. Стили можно изменять на основе пропсов, используя функцию внутри шаблонных литералов:

const Button = styled.button`   background-color: ${props => props.primary ? '#007bff' : 'white'};   color: ${props => props.primary ? 'white' : 'black'};   /* ... другие стили ... */ `;  function App() {   return (     <div>       <Button primary>Primary Button</Button>       <Button>Secondary Button</Button>     </div>   ); }

Styled Components поддерживает темизацию. Для этого можно использовать ThemeProvider:

import { ThemeProvider } from 'styled-components';  const theme = {   primaryColor: '#007bff',   secondaryColor: '#6c757d', };  const Button = styled.button`   background-color: ${props => props.primary ? props.theme.primaryColor : props.theme.secondaryColor};   /* ... другие стили ... */ `;  function App() {   return (     <ThemeProvider theme={theme}>       <div>         <Button primary>Primary Button</Button>         <Button>Secondary Button</Button>       </div>     </ThemeProvider>   ); }  export default App;

ЗдесьButton использует свойства темы для применения стилей.

Styled Components также позволяет создавать глобальные стили с помощью createGlobalStyle:

import { createGlobalStyle } from 'styled-components';  const GlobalStyle = createGlobalStyle`   body {     font-family: 'Arial', sans-serif;     background-color: #f0f0f0;   } `;  function App() {   return (     <>       <GlobalStyle />       <div>         <h1>Hello, World!</h1>       </div>     </>   ); }  export default App;

Styled Components — очень мощный инструмент. Если вы еще не пробовали его, настоятельно рекомендую!

А подробнее с библиотекой можно ознакомиться здесь

Linaria

Linaria — это zero-runtime CSS-in-JS библиотека, которая преобразует стили, написанные в JS, в отдельные CSS файлы на этапе сборки. Все это для снижения затрат на выполнение стилей во время работы приложения.

Linaria использует шаблонные литералы для определения стилей, которые затем компилируются в чистые CSS файлы. Она поддерживает фичи современного CSS: переменные, медиа-запросы, интеграцию с популярными инструментами сборки, такими как Webpack и Rollup.

Для начала использования Linaria, установим необходимые пакеты:

npm install @linaria/core @linaria/react @linaria/babel-preset

Затем настроим Babel, добавив @linaria в Babel конфиг:

{   "presets": [     "@babel/preset-env",     "@babel/preset-react",     "@linaria/babel-preset"   ] }

Linaria позволяет создавать стили с помощью функции css и компоненты с помощью styled:

import { css } from '@linaria/core';  const titleStyle = css`   font-size: 24px;   color: #333;   text-align: center; `;  function Title() {   return <h1 className={titleStyle}>Hello, Linaria!</h1>; }  export default Title;

Создали класс titleStyle и применяем его к компоненту Title.

Linaria также поддерживает создание стилизованных компонентов с функцией styled, аналогично Styled Components:

import { styled } from '@linaria/react';  const Button = styled.button`   background-color: #007bff;   color: white;   border: none;   padding: 10px 20px;   border-radius: 4px;   cursor: pointer;    &:hover {     background-color: #0056b3;   } `;  function App() {   return (     <div>       <h1>Welcome to Linaria!</h1>       <Button>Click me</Button>     </div>   ); }  export default App;

Пример использования Linaria для создания темы в React-приложении:

// theme.js export const theme = {   colors: {     primary: '#007bff',     secondary: '#6c757d',   }, };  // Button.js import { styled } from '@linaria/react'; import { theme } from './theme';  const Button = styled.button`   background-color: ${theme.colors.primary};   color: white;   border: none;   padding: 10px 20px;   border-radius: 4px;   cursor: pointer;    &:hover {     background-color: ${theme.colors.secondary};   } `;  export default Button;  // App.js import React from 'react'; import Button from './Button';  function App() {   return (     <div>       <h1>Welcome to Themed Linaria!</h1>       <Button>Click me</Button>     </div>   ); }  export default App;

Создаем тему в отдельном файле и используем ее в стилизованном компоненте Button. Стили кнопки изменяются на основе свойств темы.

Подробнее с Linaria можно ознакомиться здесь.

Emotion

Emotion — это высокопроизводительная библиотека для CSS-in-JS, поддерживающая как стильные компоненты, так и базовые CSS стили.

Emotion предлагает два основных способа написания стилей: через styled-компоненты и через css-утилиту.

Для использования Emotion, установим необходимые пакеты:

npm install @emotion/react @emotion/styled

Создание стилей с помощью css:
css — это утилита, которая позволяет определять стили как объекты или строки.

/** @jsxImportSource @emotion/react */ import { css } from '@emotion/react';  const style = css`   color: hotpink; `;  function App() {   return <div css={style}>Hello, Emotion!</div>; }  export default App;

Здесь юзаем css для определения стиля и применяем его к элементу через атрибут css.

Создание стилизованных компонентов с помощью styled:
styled позволяет создавать React-компоненты с инкапсулированными стилями.

import styled from '@emotion/styled';  const Button = styled.button`   background-color: #007bff;   color: white;   border: none;   padding: 10px 20px;   border-radius: 4px;   cursor: pointer;    &:hover {     background-color: #0056b3;   } `;  function App() {   return (     <div>       <Button>Click me</Button>     </div>   ); }  export default App;

Динамические стили:
Emotion позволяет легко применять динамические стили на основе пропсов.

const Button = styled.button`   background-color: ${props => props.primary ? '#007bff' : 'white'};   color: ${props => props.primary ? 'white' : '#007bff'};   border: 2px solid #007bff;   padding: 10px 20px;   border-radius: 4px;   cursor: pointer;    &:hover {     background-color: ${props => props.primary ? '#0056b3' : '#e0e0e0'};   } `;  function App() {   return (     <div>       <Button primary>Primary Button</Button>       <Button>Secondary Button</Button>     </div>   ); }  export default App; 

Темизация:
Emotion поддерживает темизацию через контекст и ThemeProvider.

import { ThemeProvider } from '@emotion/react';  const theme = {   colors: {     primary: '#007bff',     secondary: '#6c757d',   }, };  const Button = styled.button`   background-color: ${props => props.theme.colors.primary};   color: white;   border: none;   padding: 10px 20px;   border-radius: 4px;   cursor: pointer;    &:hover {     background-color: ${props => props.theme.colors.secondary};   } `;  function App() {   return (     <ThemeProvider theme={theme}>       <div>         <Button>Click me</Button>       </div>     </ThemeProvider>   ); }  export default App;

ЗдесьButton использует свойства темы для применения стилей, с помощью чего можно легко управлять цветовой схемой приложения.

Пример использования Emotion для создания адаптивного интерфейса:

import styled from '@emotion/styled';  const Container = styled.div`   display: flex;   flex-direction: column;   align-items: center;   padding: 20px;    @media (min-width: 600px) {     flex-direction: row;   } `;  const Item = styled.div`   background-color: #f0f0f0;   margin: 10px;   padding: 20px;   border-radius: 4px; `;  function App() {   return (     <Container>       <Item>Item 1</Item>       <Item>Item 2</Item>       <Item>Item 3</Item>     </Container>   ); }  export default App;

В этом кодеContainer меняет направление флекс-контейнера в зависимости от ширины экрана.

Документацию к Emotion можно посмотреть здесь

Stitches

Stitches предлагает удобный API, поддержку тем и динамических стилей, а также интеграцию с фреймворками и инструментами сборки

Установим библиотеку через npm или yarn:

npm install @stitches/react # или yarn add @stitches/react

Функция createStitches позволяет определить конфигурацию для стилей и создавать styled-компоненты:

import { createStitches } from '@stitches/react';  const { styled, css, globalCss, theme } = createStitches({   theme: {     colors: {       primary: '#007bff',       secondary: '#6c757d',     },     fontSizes: {       body: '16px',       heading: '24px',     },   }, });  const Button = styled('button', {   backgroundColor: '$primary',   color: 'white',   padding: '10px 20px',   borderRadius: '4px',   border: 'none',   cursor: 'pointer',    '&:hover': {     backgroundColor: '$secondary',   }, });

Создали кнопку с использованием тем и стилей, определенных в конфигурации createStitches.

Stitches позволяет задавать глобальные стили через функцию globalCss:

const globalStyles = globalCss({   body: {     margin: 0,     fontFamily: 'Arial, sans-serif',   }, });  function App() {   globalStyles();    return (     <div>       <h1>Hello, Stitches!</h1>       <Button>Click me</Button>     </div>   ); }  export default App;

Stitches позволяет легко применять динамические стили на основе пропсов:

const Button = styled('button', {   variants: {     color: {       primary: {         backgroundColor: '$primary',         color: 'white',       },       secondary: {         backgroundColor: '$secondary',         color: 'white',       },     },   },   defaultVariants: {     color: 'primary',   }, });  function App() {   return (     <div>       <Button color="primary">Primary Button</Button>       <Button color="secondary">Secondary Button</Button>     </div>   ); }  export default App;

Stitches поддерживает создание и использование тем:

const lightTheme = theme({   colors: {     background: 'white',     text: 'black',   }, });  const darkTheme = theme({   colors: {     background: 'black',     text: 'white',   }, });  const Container = styled('div', {   backgroundColor: '$background',   color: '$text',   padding: '20px',   borderRadius: '8px', });  function App() {   const [isDark, setIsDark] = React.useState(false);    return (     <div className={isDark ? darkTheme : lightTheme}>       <Container>         <h1>Hello, Stitches!</h1>         <Button onClick={() => setIsDark(!isDark)}>           Toggle Theme         </Button>       </Container>     </div>   ); }  export default App;

Пример кода Stitches для создания адаптивного интерфейса с динамическими стилями:

import { createStitches } from '@stitches/react';  const { styled, globalCss } = createStitches({   theme: {     colors: {       primary: '#007bff',       secondary: '#6c757d',     },   }, });  const globalStyles = globalCss({   body: {     margin: 0,     fontFamily: 'Arial, sans-serif',   }, });  const Container = styled('div', {   display: 'flex',   flexDirection: 'column',   alignItems: 'center',   padding: '20px',    '@media(min-width: 600px)': {     flexDirection: 'row',   }, });  const Item = styled('div', {   backgroundColor: '#f0f0f0',   margin: '10px',   padding: '20px',   borderRadius: '4px', });  function App() {   globalStyles();    return (     <Container>       <Item>Item 1</Item>       <Item>Item 2</Item>       <Item>Item 3</Item>     </Container>   ); }  export default App;

Здесь Container будет менять направление флекс-контейнера в зависимости от ширины экрана.

Как можно заметить, строчек здесь уже намного больше, чем в аналогичном примере у Emotion.

Подробнее со Stiches можно ознакомиться здесь

Vanilla-Extract

Vanilla-Extract — это zero-runtime CSS-in-JS библиотека, которая позволяет писать стили в TypeScript или JavaScript и компилировать их в статические CSS файлы на этапе сборки.

Vanilla-Extract использует функции для определения стилей и тем, которые затем компилируются в отдельные CSS файлы.

Установим:

npm install @vanilla-extract/css

Затем настроим сборщик, например Webpack, для работы с Vanilla-Extract. Для этого нужно добавить плагин в конфигурацию Webpack.

Пример настройки Webpack:

// webpack.config.js const { VanillaExtractPlugin } = require('@vanilla-extract/webpack-plugin');  module.exports = {   // ... другие настройки   plugins: [     new VanillaExtractPlugin(),   ],   module: {     rules: [       {         test: /\.css\.ts$/,         use: [           'vanilla-extract-loader',           'ts-loader',         ],       },     ],   }, };

Vanilla-Extract позволяет создавать стили с помощью функции style и тем через функцию createTheme:

// styles.css.ts import { style } from '@vanilla-extract/css';  export const button = style({   backgroundColor: 'blue',   color: 'white',   padding: '10px 20px',   borderRadius: '5px',   border: 'none',   cursor: 'pointer',   ':hover': {     backgroundColor: 'darkblue',   }, });

Стили, определенные с помощью Vanilla-Extract, можно использовать в компонентах React или других фреймворках:

// Button.tsx import React from 'react'; import { button } from './styles.css.ts';  const Button: React.FC = () => {   return <button className={button}>Click me</button>; };  export default Button;

Пример использования Vanilla-Extract для создания адаптивного интерфейса с динамическими стилями и темами:

// responsive.css.ts import { style } from '@vanilla-extract/css';  export const container = style({   display: 'flex',   flexDirection: 'column',   alignItems: 'center',   padding: '20px',    '@media': {     '(min-width: 600px)': {       flexDirection: 'row',     },   }, });  export const item = style({   backgroundColor: '#f0f0f0',   margin: '10px',   padding: '20px',   borderRadius: '5px', });
// App.tsx import React from 'react'; import { container, item } from './responsive.css.ts';  const App: React.FC = () => {   return (     <div className={container}>       <div className={item}>Item 1</div>       <div className={item}>Item 2</div>       <div className={item}>Item 3</div>     </div>   ); };  export default App;

Container меняет направление флекс‑контейнера в зависимости от ширины экрана.

Подробнее — здесь

Финальные слова

Все представленные инструменты в статье хороши по своему и каждый может найти свой по вкусу. Хотелось бы услышать о вашем опыте работы с CSS-in-JS, какие инструменты использовали и какие нюансы могли бы рассказать?


Все актуальные методы и инструменты веб-разработки можно освоить на онлайн-курсах OTUS: в каталоге можно посмотреть список всех программ, а в календаре — записаться на открытые уроки.


ссылка на оригинал статьи https://habr.com/ru/articles/829322/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *