CSS Relative Color Syntax: полное руководство для разработчиков
Руководство · Обновлено 2026

CSS Relative Color Syntax:
Создавайте динамические цветовые системы без препроцессоров

Всё, что нужно знать о CSS Relative Color Syntax в 2026 году — от базового синтаксиса до построения полноценных систем дизайн-токенов. Практические примеры кода, реальные сценарии и стратегии миграции от senior frontend-разработчика.

Олег Максимов 29 мая 2026 18 мин чтения

Введение

Долгие годы, если вам нужно было получить более светлый вариант фирменного цвета, полупрозрачную подложку или комплементарный оттенок для ховера, было два пути: Sass-функции (вроде lighten(), darken(), saturate()) или ручной подбор цветов в пикере. Оба подхода статичны — вы фиксируете производный цвет на этапе сборки или дизайна, и он никогда не меняется.

CSS Relative Color Syntax меняет это кардинально. Он позволяет взять любой цвет — CSS-переменную, именованный цвет, hex-значение — и создать на его основе новые цвета в браузере в реальном времени. Ваши дизайн-токены становятся динамическими: пользователь меняет --brand-color, и все ховеры, варианты границ и фоновые оттенки обновляются автоматически.

В этом руководстве я разберу полный синтаксис, все практические паттерны манипуляции цветом, построение систем дизайн-токенов и миграцию с Sass на нативные CSS-функции работы с цветом.

Что такое CSS Relative Color Syntax?

CSS Relative Color Syntax позволяет создать новый цвет на основе существующего исходного цвета. Ключевой элемент — ключевое слово from внутри любой CSS-цветовой функции:

/* Общий паттерн */
background: rgb(from var(--brand) r g b);
background: oklch(from #6366f1 l c h);
background: hsl(from indigo h s l);

Браузер берёт исходный цвет, конвертирует его в целевое цветовое пространство и разбирает на именованные переменные каналов. Вы можете использовать эти переменные как есть или изменять их с помощью calc():

/* Тот же цвет — без изменений */
.exact-copy {
  background: rgb(from #6366f1 r g b);
  /* То же самое, что #6366f1 */
}

/* С изменением — на 20% светлее */
.lighter {
  background: oklch(from #6366f1 calc(l + 0.2) c h);
}

💡 Ключевое понимание: Имена переменных каналов зависят от выходной цветовой функции, а не от исходного цвета. Если вы передаёте hex-значение в oklch(), браузер конвертирует hex → OKLCH и даёт вам l, c, h. Если передаёте OKLCH в rgb(), получаете r, g, b.

Выбор цветового пространства: почему OKLCH лучший

CSS Relative Color Syntax работает с любой цветовой функцией — rgb(), hsl(), hwb(), lab(), lch(), oklch(), oklab() и color(). Но выбор цветового пространства кардинально влияет на качество манипуляций.

Пространство Переменные каналов Лучше всего для Недостаток
rgb() r g b Простая прозрачность, прямая работа со значениями Неперцептивно равномерно; каналы RGB неинтуитивны для сдвига оттенка
hsl() h s l Поворот оттенка, насыщенность Яркость не перцептивно равномерна — одинаковое изменение даёт разный визуал
lch() l c h Перцептивно равномерная яркость и хрома Может выходить за границы sRGB
oklch() l c h Всё — равномерность + безопасность sRGB Угол оттенка немного отличается от HSL
lab() l a b Научное цветосогласование, точный контроль каналов Оси a и b неинтуитивны

OKLCH — рекомендуемый выбор по умолчанию для программной работы с цветом. Он перцептивно равномерен (одинаковое изменение = одинаковый визуальный эффект при любом оттенке), остаётся в границах sRGB (нет неожиданных выбросов), а его каналы l (светлота), c (хрома/насыщенность), h (оттенок) интуитивно соответствуют операциям, которые нужны разработчикам: осветление/затемнение (L), насыщение/обесцвечивание (C), сдвиг оттенка (H).

Справочник переменных каналов

Каждая цветовая функция предоставляет специфические имена переменных каналов:

Функция Канал 1 Канал 2 Канал 3 Альфа
rgb() r (0–255) g (0–255) b (0–255) alpha / a
hsl() h (0–360) s (0–100%) l (0–100%) alpha
hwb() h (0–360) w (0–100%) b (0–100%) alpha
oklch() l (0–1) c (0–0.4) h (0–360) alpha
oklab() l (0–1) a (−0.4–0.4) b (−0.4–0.4) alpha
lab() l (0–100) a (−125–125) b (−125–125) alpha
lch() l (0–100) c (0–150) h (0–360) alpha

💡 Примечание: В oklch() светлота l изменяется от 0 до 1 (0 = чёрный, 1 = белый), а хрома c — от 0 до примерно 0.37 для sRGB-цветов. Хрома 0 = серый. В hsl() насыщенность и светлота — проценты (0%–100%), а оттенок — градусы (0–360).

Практические паттерны манипуляции цветом

1. Осветление цвета

Увеличьте светлоту (l), добавив дельту. В OKLCH добавление 0.05 даёт заметно, но ненавязчиво более светлый вариант — одинаково для всех оттенков:

.card {
  background: oklch(from var(--surface) l c h);
}

.card:hover {
  /* На 10% светлее */
  background: oklch(from var(--surface) calc(l + 0.1) c h);
}

2. Затемнение цвета

Уменьшите светлоту. В OKLCH вычитайте из l:

.modal-overlay {
  /* На 30% темнее фона страницы */
  background: oklch(from var(--bg) calc(l - 0.3) 0.01 h);
  /* Почти чёрный, обесцвеченный */
}

3. Изменение насыщенности (хромы)

В OKLCH хрома (c) управляет насыщенностью. Ноль = серый. Увеличьте для яркости, уменьшите для приглушённости:

.muted-text {
  /* Обесцвечиваем брендовый цвет для второстепенного текста */
  color: oklch(from var(--brand) l calc(c * 0.3) h);
}

.vivid-hover {
  /* Усиливаем насыщенность при наведении */
  color: oklch(from var(--brand) l calc(c * 1.4) h);
}

4. Изменение прозрачности (альфа-канал)

Альфа-канал доступен как alpha во всех цветовых функциях:

.overlay {
  /* 30% прозрачности брендового цвета */
  background: oklch(from var(--brand) l c h / 0.3);
}

.on-scroll-header {
  /* Полупрозрачный — 80% от исходной прозрачности */
  background: oklch(from var(--header-bg) l c h / calc(alpha * 0.8));
}

5. Поворот оттенка (комплементарные цвета)

Сдвиг оттенка для создания комплементарных или аналоговых цветов. Добавление 180 градусов даёт комплементарный цвет:

.danger-button {
  background: var(--brand);
}

.danger-button:hover {
  /* Поворот оттенка на 180° = комплементарный цвет */
  background: oklch(from var(--brand) l c calc(h + 180));
}

/* Аналоговый: сдвиг на 30° */
.secondary-brand {
  color: oklch(from var(--brand) l c calc(h + 30));
}

6. Инвертирование цвета

Инверсия в OKLCH использует комплемент светлоты (1 - l) и поворот оттенка на 180 градусов:

.inverted {
  background: oklch(from var(--surface) calc(1 - l) c calc(h + 180));
}

7. Фокусные кольца с доступным контрастом

Генерация фокусного кольца, работающего на любом фоне:

*:focus-visible {
  outline: 2px solid;
  /* Инвертируем и осветляем для видимости */
  outline-color: oklch(from var(--bg) calc(1 - l) c calc(h + 180));
  outline-offset: 2px;
}

Построение динамической системы дизайн-токенов

Вот где CSS Relative Color Syntax раскрывается в полную силу — создание целой цветовой системы из одной базовой CSS-переменной:

:root {
  /* Единственный источник истины */
  --brand: #6366f1;
  --brand-hover:     oklch(from var(--brand) calc(l + 0.07) c h);
  --brand-active:    oklch(from var(--brand) calc(l - 0.05) calc(c * 0.8) h);
  --brand-subtle:   oklch(from var(--brand) calc(l + 0.2) calc(c * 0.3) h);
  --brand-bg:       oklch(from var(--brand) calc(l + 0.35) calc(c * 0.15) h / 0.3);
  --brand-text:     oklch(from var(--brand) calc(l - 0.15) calc(c * 0.5) h);
  --brand-border:   oklch(from var(--brand) l calc(c * 0.6) h / 0.4);
  --brand-complement: oklch(from var(--brand) l c calc(h + 180));
}

/* Тёмная тема — меняем базовый цвет, всё обновляется */
[data-theme="dark"] {
  --brand: #a5b4fc;
  /* Все --brand-* токены пересчитываются автоматически */
}

Измените --brand в одном месте, и все производные цвета — ховер, активный, фоновый, текстовый, граница, комплемент — обновятся автоматически. Это невозможно в Sass, где производные цвета вычисляются на этапе сборки.

Миграция с Sass на нативный CSS

Если вы используете Sass-систему цветов, вот соответствие операций:

Операция Sass CSS Relative Color (OKLCH)
Осветлить lighten($color, 10%) oklch(from var(--c) calc(l + 0.1) c h)
Затемнить darken($color, 10%) oklch(from var(--c) calc(l - 0.1) c h)
Насытить saturate($color, 20%) oklch(from var(--c) l calc(c * 1.2) h)
Обесцветить desaturate($color, 30%) oklch(from var(--c) l calc(c * 0.7) h)
Изменить прозрачность rgba($color, 0.5) oklch(from var(--c) l c h / 0.5)
Комплемент complement($color) oklch(from var(--c) l c calc(h + 180))
Смешивание mix($a, $b, 50%) Используйте color-mix()

Большинство операций имеют прямой эквивалент. Единственное исключение — mix() — для него в CSS есть функция color-mix(). Вместе color-mix() и CSS Relative Color Syntax покрывают все практические операции с цветом.

Работа с CSS-переменными

CSS Relative Color Syntax отлично работает с CSS-переменными. Именно здесь динамическая природа раскрывается в полной мере:

.themed-card {
  /* Принимает любой цвет бренда */
  --card-brand: var(--accent);
  background: oklch(from var(--card-brand) calc(l + 0.35) calc(c * 0.1) h / 0.4);
  border: 1px solid oklch(from var(--card-brand) l calc(c * 0.5) h / 0.3);
  color: oklch(from var(--card-brand) calc(l - 0.2) calc(c * 0.6) h);
}

/* Использование в разных контекстах */
.card-primary { --card-brand: var(--brand); }
.card-success { --card-brand: var(--success); }
.card-warning { --card-brand: var(--warning); }

Поддержка браузеров и прогрессивное улучшение

По состоянию на май 2026 года CSS Relative Color Syntax имеет ~90% глобальной поддержки браузеров:

Для запасного варианта используйте CSS-каскад — объявите резервное значение первым, затем относительный цвет:

.btn-primary {
  /* Запасной вариант для старых браузеров */
  background: #818cf8;
  /* Современный браузер переопределит */
  background: oklch(from var(--brand) calc(l + 0.07) c h);
}

Реальные примеры компонентов

Система кнопок с динамическими цветами

.btn {
  --btn-bg: var(--brand);
  background: var(--btn-bg);
  border: 1px solid oklch(from var(--btn-bg) calc(l - 0.1) c h);
  transition: background 0.2s;
}

.btn:hover {
  background: oklch(from var(--btn-bg) calc(l + 0.07) calc(c * 1.15) h);
}

.btn:active {
  background: oklch(from var(--btn-bg) calc(l - 0.05) calc(c * 0.9) h);
}

.btn-danger   { --btn-bg: var(--danger); }
.btn-success  { --btn-bg: var(--success); }
.btn-warning  { --btn-bg: var(--warning); }

Адаптивный контраст текста

.auto-contrast-text {
  --bg: var(--section-bg);
  /* Тёмный текст на светлом фоне, светлый на тёмном */
  color: oklch(from var(--bg) calc(1 - l) 0.02 h);
}

Заключение

CSS Relative Color Syntax — одна из самых transformative возможностей CSS в 2020-х. Она устраняет последнюю серьёзную причину использовать CSS-препроцессор — динамическую работу с цветом — и даёт возможность создавать полностью адаптивные, вычисляемые в реальном времени системы дизайн-токенов в нативном CSS.

Начните с одной базовой CSS-переменной и трёх производных вариантов. По мере освоения расширяйтесь до полных систем токенов — и вы больше никогда не вернётесь к пикеру цветов или Sass-функциям для большинства операций с цветом.

Нужна помощь с внедрением современной CSS-системы цветов в вашем проекте? Я занимаюсь фронтенд-архитектурой и разработкой. Посмотрите мои услуги или свяжитесь со мной для консультации.

Контакты

Разрабатываете современное веб-приложение?

Я создаю production-веб-приложения на современном CSS и JavaScript. Расскажите о задаче — бесплатная консультация.