Всё, что нужно знать о CSS Relative Color Syntax в 2026 году — от базового синтаксиса до построения полноценных систем дизайн-токенов. Практические примеры кода, реальные сценарии и стратегии миграции от senior frontend-разработчика.
Долгие годы, если вам нужно было получить более светлый вариант фирменного цвета,
полупрозрачную подложку или комплементарный оттенок для ховера, было два пути:
Sass-функции (вроде lighten(), darken(),
saturate()) или ручной подбор цветов в пикере. Оба
подхода статичны — вы фиксируете производный цвет на этапе сборки или дизайна,
и он никогда не меняется.
CSS Relative Color Syntax меняет это кардинально. Он позволяет взять
любой цвет — CSS-переменную, именованный цвет, hex-значение — и создать на его основе
новые цвета в браузере в реальном времени. Ваши дизайн-токены становятся
динамическими: пользователь меняет --brand-color, и все ховеры,
варианты границ и фоновые оттенки обновляются автоматически.
В этом руководстве я разберу полный синтаксис, все практические паттерны манипуляции цветом, построение систем дизайн-токенов и миграцию с Sass на нативные CSS-функции работы с цветом.
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.
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).
Увеличьте светлоту (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); }
Уменьшите светлоту. В OKLCH вычитайте из l:
.modal-overlay { /* На 30% темнее фона страницы */ background: oklch(from var(--bg) calc(l - 0.3) 0.01 h); /* Почти чёрный, обесцвеченный */ }
В 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); }
Альфа-канал доступен как 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)); }
Сдвиг оттенка для создания комплементарных или аналоговых цветов. Добавление 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)); }
Инверсия в OKLCH использует комплемент светлоты (1 - l) и
поворот оттенка на 180 градусов:
.inverted { background: oklch(from var(--surface) calc(1 - l) c calc(h + 180)); }
Генерация фокусного кольца, работающего на любом фоне:
*: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-систему цветов, вот соответствие операций:
| Операция | 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 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. Расскажите о задаче — бесплатная консультация.