Привет, Хабр!
В одном из проектов мне нужно было создать сложную админку для крупного клиента. Интерфейс требовал большо количества интерактивностей, а также поддержку различных тем и динамических стилей. Именно тогда я решил обратить свой взгляд на CSS‑in‑JS библиотеки, и это для меня стало большим открытием.
Ведь стилизация компонентов — основа для создания интуитивно понятных и эстетически приятных интерфейсов. И иногда традиционные методы стилизации, такие как CSS‑файлы или препроцессоры, имеют свои ограничения и могут усложнять сам процесс разработки, чего мы точно не хотим.
Здесь вот и приходят на помощь решения CSS‑in‑JS, объединяющие фичи JS и CSS.
CSS‑in‑JS — это подход к стилизации, который позволяет писать стили прямо в JavaScript‑коде. Преимущества такого подхода:
-
Изоляция стилей: компоненты получают свои собственные стили.
-
Динамические стили: легко применять стили в зависимости от состояния компонента или пропсов.
-
Поддержка тем: удобное управление темами и их переключение на лету.
-
Интеграция с 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/
Добавить комментарий