Архитектура дизайн-систем на практике: Полный путь от Design Tokens до библиотек компонентов
Трёхслойная архитектура дизайн-систем
┌─────────────────────────────────┐
│ Слой компонентов │ Button, Card, Modal...
├─────────────────────────────────┤
│ Слой паттернов │ Формы, Навигация, Таблицы данных
├─────────────────────────────────┤
│ Слой токенов (Design Tokens) │ Цвета, Отступы, Размеры шрифтов, Тени
└─────────────────────────────────┘
Токены — это фундамент, паттерны — это композиция, компоненты — это конечная точка. Строить снизу вверх, потреблять сверху вниз.
Система Design Tokens
1. Токены цветов
/* Трёхслойные семантические токены */
/* Слой 1: Примитивные значения */
:root {
--blue-50: #eff6ff;
--blue-500: #3b82f6;
--blue-700: #1d4ed8;
--gray-50: #f9fafb;
--gray-900: #111827;
--red-500: #ef4444;
--green-500: #22c55e;
}
/* Слой 2: Семантическое отображение */
:root {
--color-primary: var(--blue-500);
--color-primary-hover: var(--blue-700);
--color-surface: var(--gray-50);
--color-text: var(--gray-900);
--color-danger: var(--red-500);
--color-success: var(--green-500);
}
/* Слой 3: На уровне компонента */
:root {
--button-bg: var(--color-primary);
--button-bg-hover: var(--color-primary-hover);
--button-text: white;
--input-border: var(--color-border);
--input-border-focus: var(--color-primary);
}
2. Токены отступов (Сетка 8pt)
:root {
--space-0: 0;
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.5rem; /* 24px */
--space-6: 2rem; /* 32px */
--space-8: 3rem; /* 48px */
--space-10: 4rem; /* 64px */
}
3. Токены типографики
:root {
/* Размеры шрифтов */
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
/* Межстрочные интервалы */
--leading-tight: 1.25;
--leading-normal: 1.5;
--leading-relaxed: 1.75;
/* Начертания шрифтов */
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
}
4. Токены теней
:root {
--shadow-xs: 0 1px 2px rgba(0,0,0,0.05);
--shadow-sm: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);
--shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.06);
--shadow-lg: 0 10px 15px rgba(0,0,0,0.1), 0 4px 6px rgba(0,0,0,0.05);
--shadow-xl: 0 20px 25px rgba(0,0,0,0.1), 0 8px 10px rgba(0,0,0,0.04);
}
Механизм переключения тем
Подход с CSS-переменными
/* Светлая тема (по умолчанию) */
:root {
--color-surface: #ffffff;
--color-text: #111827;
--color-border: #e5e7eb;
--color-primary: #3b82f6;
}
/* Тёмная тема */
[data-theme="dark"] {
--color-surface: #1f2937;
--color-text: #f9fafb;
--color-border: #374151;
--color-primary: #60a5fa;
}
/* Тема с высоким контрастом */
[data-theme="high-contrast"] {
--color-surface: #000000;
--color-text: #ffffff;
--color-border: #ffffff;
--color-primary: #ffff00;
}
Переключение тем в React
import { useEffect, useState } from 'react';
type Theme = 'light' | 'dark' | 'system';
function useTheme() {
const [theme, setTheme] = useState<Theme>(() => {
return (localStorage.getItem('theme') as Theme) || 'system';
});
useEffect(() => {
const root = document.documentElement;
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const resolved = theme === 'system' ? (systemDark ? 'dark' : 'light') : theme;
root.setAttribute('data-theme', resolved);
localStorage.setItem('theme', theme);
}, [theme]);
return { theme, setTheme };
}
Тёмный режим Tailwind CSS v4
/* tailwind.config.ts в режиме CSS-переменных */
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
<!-- Автоматическая адаптация к теме -->
<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100">
Контент автоматически адаптируется к текущей теме
</div>
Принципы проектирования API компонентов
1. Единственная ответственность + Композиция прежде всего
// ❌ Переинкапсуляция: Все функции запихнуты в один компонент
<SuperButton variant="primary" size="lg" icon="save" loading disabled />
// ✅ Паттерн композиции: Сборка через дочерние компоненты
<Button variant="primary" size="lg">
<Icon name="save" />
<Button.Label>Сохранить</Button.Label>
<Button.Loading />
</Button>
2. Контролируемый vs Неконтролируемый
// Контролируемый режим: Состояние управляется извне
<Input value={value} onChange={setValue} />
// Неконтролируемый режим: Состояние управляется внутри компонента
<Input defaultValue="hello" onChange={handleChange} />
// Совместимость с обоими
interface InputProps {
value?: string; // Контролируемый
defaultValue?: string; // Неконтролируемый
onChange?: (value: string) => void;
}
3. Полиморфные компоненты
// Button может рендериться как button, a или Link из Next.js
type ButtonProps<C extends React.ElementType = 'button'> = {
as?: C;
} & React.ComponentPropsWithoutRef<C>;
function Button<C extends React.ElementType = 'button'>(
{ as, ...props }: ButtonProps<C>
) {
const Component = as || 'button';
return <Component className="btn" {...props} />;
}
// Использование
<Button>Нажать</Button>
<Button as="a" href="/link">Ссылка</Button>
<Button as={Link} to="/page">Ссылка маршрута</Button>
4. Паттерн Slots
// Дизайн Slots компонента Card
interface CardSlots {
header?: React.ReactNode;
media?: React.ReactNode;
content: React.ReactNode;
footer?: React.ReactNode;
actions?: React.ReactNode;
}
function Card({ header, media, content, footer, actions }: CardSlots) {
return (
<div className="card">
{header && <div className="card-header">{header}</div>}
{media && <div className="card-media">{media}</div>}
<div className="card-content">{content}</div>
{footer && <div className="card-footer">{footer}</div>}
{actions && <div className="card-actions">{actions}</div>}
</div>
);
}
Мультибрендовая адаптация
Слой переопределения бренда
/* Базовые токены (Бренд A) */
:root {
--brand-primary: #3b82f6;
--brand-radius: 8px;
--brand-font: 'Inter', sans-serif;
}
/* Переопределение Бренд B */
[data-brand="b"] {
--brand-primary: #8b5cf6;
--brand-radius: 12px;
--brand-font: 'Poppins', sans-serif;
}
/* Переопределение Бренд C */
[data-brand="c"] {
--brand-primary: #f59e0b;
--brand-radius: 4px;
--brand-font: 'Roboto', sans-serif;
}
Пайплайн компиляции токенов
Исходные файлы дизайна (Figma)
↓
Компиляция Style Dictionary
↓
├── CSS-переменные (Web)
├── Конфигурация Tailwind (Tailwind-проекты)
├── iOS Swift-файлы
├── Android Kotlin-файлы
└── JSON (Сайт документации)
// style-dictionary.config.js
const StyleDictionary = require('style-dictionary');
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'dist/css/',
files: [{ destination: 'variables.css', format: 'css/variables' }],
},
tailwind: {
transformGroup: 'js',
buildPath: 'dist/tailwind/',
files: [{ destination: 'theme.js', format: 'javascript/module' }],
},
},
};
Практики дизайн-системы ToolsKu
ToolsKu использует Tailwind CSS v4 + CSS-переменные для создания своей дизайн-системы:
/* Токены темы ToolsKu */
:root {
--color-primary: #2563eb;
--color-surface: #ffffff;
--color-text: #1f2937;
--radius: 8px;
--font-sans: 'Inter', system-ui, sans-serif;
}
/* Компонент карточки инструмента */
.tool-card {
padding: var(--space-4);
border-radius: var(--radius);
background: var(--color-surface);
border: 1px solid var(--color-border);
transition: transform 0.2s, box-shadow 0.2s;
}
.tool-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
Управление дизайн-системой
Управление версиями
@toolsku/tokens v2.4.0 → Пакет Design Tokens
@toolsku/components v3.1.0 → Библиотека компонентов
@toolsku/patterns v1.2.0 → Библиотека паттернов
Цепочка зависимостей: patterns → components → tokens
Рабочий процесс изменений
1. Дизайнер изменяет токены в Figma
2. Авто-синхронизация в Git-репозиторий (Плагин Figma)
3. CI запускает компиляцию Style Dictionary
4. Визуальные регрессионные тесты (Chromatic/Storybook)
5. Авто-публикация новой версии (Changesets)
Сайт документации
Storybook
├── Tokens → Демонстрация цветов, отступов, размеров шрифтов
├── Components → Документация взаимодействия компонентов
├── Patterns → Руководство по использованию паттернов
└── Guidelines → Документация дизайн-спецификаций
Итоги
Дизайн-система — это не просто библиотека компонентов, а полная архитектура от Токенов до Компонентов до Паттернов. Трёхслойные токены (Примитивные → Семантические → Компонентные) — основа масштабируемости. Паттерны композиции превосходят переинкапсуляцию, а CSS-переменные + Tailwind — самый практичный технологический выбор в 2026 году. Помните: хорошая дизайн-система позволяет дизайнерам и разработчикам говорить на одном языке, а токены — это словарный запас этого языка.
Попробуйте эти локальные браузерные инструменты — регистрация не требуется →