Реализация CSS-in-JS решения для компонентов

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация CSS-in-JS решения для компонентов
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Реализация CSS-in-JS решения для компонентов

CSS-in-JS — подход, при котором стили определяются непосредственно в JavaScript/TypeScript коде компонента. Стили изолированы, типизированы, могут использовать props и переменные без CSS-переменных. За это платят либо runtime-затратами (styled-components, Emotion), либо необходимостью настройки сборки (vanilla-extract, Linaria).

Выбор библиотеки

Библиотека Runtime SSR Bundle Когда выбирать
Emotion Да Да ~8KB React-проекты, нужна динамика
styled-components Да Да ~13KB Классика, большая экосистема
vanilla-extract Нет Да 0 Статические стили, максимум производительности
Linaria Нет Да 0 Babel/Vite, статика с интерполяцией
Panda CSS Нет Да 0 Atomic, design tokens, современный проект

Для нового React-проекта — vanilla-extract (zero-runtime) или Emotion (если нужны динамические стили через props).

Emotion: базовая настройка

npm install @emotion/react @emotion/styled
npm install -D @emotion/babel-plugin  # для оптимизации
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: ['@emotion/babel-plugin'],
      },
    }),
  ],
})

Styled Components с Emotion

import styled from '@emotion/styled'
import { css } from '@emotion/react'

// Базовый styled component
const Button = styled.button<{
  variant?: 'primary' | 'secondary' | 'ghost'
  size?: 'sm' | 'md' | 'lg'
}>`
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border-radius: ${({ theme }) => theme.radii.md};
  font-weight: 500;
  cursor: pointer;
  transition: background-color 150ms ease, transform 100ms ease;

  &:active { transform: scale(0.98); }
  &:disabled { opacity: 0.5; cursor: not-allowed; }

  ${({ size = 'md' }) =>
    ({
      sm: css`padding: 6px 12px; font-size: 13px;`,
      md: css`padding: 10px 20px; font-size: 14px;`,
      lg: css`padding: 14px 28px; font-size: 16px;`,
    }[size])}

  ${({ variant = 'primary', theme }) =>
    ({
      primary: css`
        background: ${theme.colors.primary};
        color: white;
        border: none;
        &:hover { background: ${theme.colors.primaryHover}; }
      `,
      secondary: css`
        background: transparent;
        color: ${theme.colors.primary};
        border: 2px solid ${theme.colors.primary};
        &:hover { background: ${theme.colors.primaryLight}; }
      `,
      ghost: css`
        background: transparent;
        color: ${theme.colors.text};
        border: none;
        &:hover { background: ${theme.colors.bgHover}; }
      `,
    }[variant])}
`

css prop

import { css } from '@emotion/react'

function Card({ featured }: { featured?: boolean }) {
  return (
    <div
      css={css`
        background: ${featured ? '#eff6ff' : '#fff'};
        border: 1px solid ${featured ? '#bfdbfe' : '#e2e8f0'};
        border-radius: 12px;
        padding: 24px;
        box-shadow: ${featured ? '0 4px 12px rgb(37 99 235 / 0.15)' : '0 1px 3px rgb(0 0 0 / 0.08)'};
        transition: box-shadow 200ms ease;

        &:hover {
          box-shadow: 0 8px 24px rgb(0 0 0 / 0.12);
        }
      `}
    >
      {/* содержимое */}
    </div>
  )
}

vanilla-extract: нулевой runtime

npm install @vanilla-extract/css
npm install -D @vanilla-extract/vite-plugin
// vite.config.ts
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'

export default defineConfig({
  plugins: [react(), vanillaExtractPlugin()],
})
// button.css.ts — статические стили, генерируются в CSS при сборке
import { styleVariants, style } from '@vanilla-extract/css'

export const base = style({
  display: 'inline-flex',
  alignItems: 'center',
  gap: '8px',
  borderRadius: '8px',
  fontWeight: 500,
  cursor: 'pointer',
  transition: 'background-color 150ms ease',

  ':disabled': {
    opacity: 0.5,
    cursor: 'not-allowed',
  },
})

export const variants = styleVariants({
  primary: {
    background: '#2563eb',
    color: 'white',
    border: 'none',
    ':hover': { background: '#1d4ed8' },
  },
  secondary: {
    background: 'transparent',
    color: '#2563eb',
    border: '2px solid #2563eb',
  },
  ghost: {
    background: 'transparent',
    color: '#0f172a',
    border: 'none',
    ':hover': { background: '#f8fafc' },
  },
})

export const sizes = styleVariants({
  sm: { padding: '6px 12px', fontSize: '13px' },
  md: { padding: '10px 20px', fontSize: '14px' },
  lg: { padding: '14px 28px', fontSize: '16px' },
})
// Button.tsx
import { base, variants, sizes } from './button.css'
import clsx from 'clsx'

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: keyof typeof variants
  size?: keyof typeof sizes
}

export function Button({ variant = 'primary', size = 'md', className, ...props }: ButtonProps) {
  return (
    <button
      className={clsx(base, variants[variant], sizes[size], className)}
      {...props}
    />
  )
}

Тема и design tokens в vanilla-extract

// theme.css.ts
import { createTheme, createThemeContract } from '@vanilla-extract/css'

// Контракт — описывает форму темы
export const vars = createThemeContract({
  color: {
    primary: null,
    bg: null,
    text: null,
  },
  radius: {
    md: null,
  },
})

// Конкретные темы
export const lightTheme = createTheme(vars, {
  color: { primary: '#2563eb', bg: '#ffffff', text: '#0f172a' },
  radius: { md: '8px' },
})

export const darkTheme = createTheme(vars, {
  color: { primary: '#3b82f6', bg: '#0f172a', text: '#f1f5f9' },
  radius: { md: '8px' },
})
// Применение темы
import { lightTheme, darkTheme } from './theme.css'

function App({ isDark }: { isDark: boolean }) {
  return (
    <div className={isDark ? darkTheme : lightTheme}>
      {/* все дочерние компоненты используют vars */}
    </div>
  )
}

Что входит в работу

Выбор подхода под проект (runtime vs zero-runtime), настройка Vite-плагинов, реализация базовых styled компонентов, система тем через ThemeProvider или createTheme, типизация props, интеграция с дизайн-системой проекта.

Срок: 1 день на настройку и перевод существующих компонентов на CSS-in-JS. Больше — при большой кодовой базе.