Уроки

Синтаксис относительных цветов CSS: динамическое преобразование цветов

7 мин чтения

CSS давно умеет хранить цвета, но для их преобразования требовался JavaScript, функции Sass или этап сборки. Синтаксис относительных цветов CSS это меняет. Он позволяет взять существующий цвет — из переменной, ключевого слова или любого значения — и преобразовать конкретные каналы прямо в таблице стилей. Можно осветлить, сдвинуть оттенок, снизить хроматичность или изменить прозрачность — всё в чистом CSS, во время выполнения.

Эта функция появилась в Chrome 119, Firefox 128 и Safari 16.4, обеспечивая достаточное покрытие браузерами для использования в production в 2026 году. Работает со всеми современными CSS-функциями цвета: rgb(), hsl(), oklch(), lab(), lch() и другими.

Что такое синтаксис относительных цветов?

Синтаксис относительных цветов расширяет любую CSS-функцию цвета конструкцией from <color> в начале. Это говорит браузеру разложить исходный цвет на каналы, а затем скомпоновать новый цвет с использованием этих каналов — возможно, с модификациями.

Самый базовый пример использует ключевое слово from для передачи цвета без изменений:

/* Операция без изменений — производит тот же цвет, что и на входе */
color: oklch(from #3B82F6 l c h);

Само по себе не очень полезно, но настоящая мощь раскрывается при модификации извлечённых значений каналов:

/* Осветлить, увеличив L (светлоту) */
color: oklch(from #3B82F6 calc(l + 0.15) c h);

/* Сдвинуть оттенок на 30 градусов */
color: oklch(from #3B82F6 l c calc(h + 30));

/* Обесцветить, снизив хроматичность */
color: oklch(from #3B82F6 l calc(c * 0.5) h);

/* Сделать полупрозрачным */
color: oklch(from #3B82F6 l c h / 0.5);

Каждое из этих преобразований меняет один канал, оставляя остальные нетронутыми — ранее это было невозможно в чистом CSS без препроцессора.

Ключевое слово from

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

color-function(from <origin-color> <channel1> <channel2> <channel3> [/ <alpha>])

<origin-color> может быть любым допустимым CSS-значением цвета:

/* Из hex-кода */
oklch(from #FF5733 l c h)

/* Из именованного цвета */
oklch(from tomato l c h)

/* Из CSS-кастомного свойства */
oklch(from var(--brand-color) l c h)

/* Из другой функции цвета */
oklch(from rgb(59, 130, 246) l c h)

/* Из currentColor */
oklch(from currentColor l c h)

Вариант from currentColor особенно мощный — позволяет компоненту трансформировать унаследованный цвет текста, не зная его точного значения.

Имена каналов по функциям цвета

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

Функция Канал 1 Канал 2 Канал 3 Альфа
oklch() l c h alpha
oklab() l a b alpha
hsl() h s l alpha
rgb() r g b alpha
lab() l a b alpha
lch() l c h alpha

Обратите внимание: в hsl() порядок каналов при from-разложении совпадает с сигнатурой функции: h, s, l. В oklch() это l, c, h. Всегда проверяйте порядок каналов для используемой функции.

Межфункциональная конвертация

Исходный цвет не обязан совпадать с выходной функцией. Браузер конвертирует автоматически:

/* Вход — hex, выход — oklch: браузер сначала конвертирует, потом разлагает */
oklch(from #FF5733 calc(l + 0.1) c h)

/* Вход — hsl, выход — rgb */
rgb(from hsl(200, 80%, 50%) calc(r * 0.9) g b)

Межфункциональная конвертация означает, что можно хранить дизайн-токены в любом формате и производить вывод в любом формате, удобном для манипуляций.

Регулировка отдельных каналов

Наиболее распространённые операции с относительными цветами включают calc() для модификации извлечённых значений каналов.

Регулировка светлоты (OKLCH)

В OKLCH канал l варьируется от 0 (чёрный) до 1 (белый). Прибавление или вычитание фиксированного значения предсказуемо осветляет или затемняет, поскольку светлота OKLCH перцептуально равномерна:

:root {
  --base: oklch(0.58 0.20 250);
}

.lighter  { color: oklch(from var(--base) calc(l + 0.15) c h); }
.lightest { color: oklch(from var(--base) calc(l + 0.30) c h); }
.darker   { color: oklch(from var(--base) calc(l - 0.15) c h); }
.darkest  { color: oklch(from var(--base) calc(l - 0.30) c h); }

Поскольку светлота OKLCH перцептуально откалибрована, прибавление 0,15 к l даёт одинаковое воспринимаемое изменение яркости независимо от оттенка — в отличие от HSL, где тот же инкремент выглядит по-разному для жёлтого и синего.

Регулировка хроматичности

Канал c управляет интенсивностью цвета. Установка в 0 даёт нейтральный серый той же светлоты. Снижение обесцвечивает без полного обесцвечивания:

/* Приглушённый вариант — 50% снижение хроматичности */
color: oklch(from var(--brand) l calc(c * 0.5) h);

/* Полное обесцвечивание при той же светлоте */
color: oklch(from var(--brand) l 0 h);

/* Более насыщенный — 30% больше хроматичности (может выйти за пределы sRGB) */
color: oklch(from var(--brand) l calc(c * 1.3) h);

Сдвиг оттенка

Канал h — значение в градусах от 0 до 360. Прибавление или вычитание сдвигает оттенок по цветовому кругу:

/* Комплементарный цвет — противоположная сторона круга */
color: oklch(from var(--brand) l c calc(h + 180));

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

/* Аналоговый -30° */
color: oklch(from var(--brand) l c calc(h - 30));

Объединение нескольких корректировок каналов создаёт сложные преобразования в одном объявлении:

/* Светлее, приглушённее и с немного другим оттенком — тональный вариант */
color: oklch(from var(--brand) calc(l + 0.12) calc(c * 0.6) calc(h + 15));

Альфа-канал

Используйте синтаксис косой черты для изменения прозрачности:

/* Версия фирменного цвета с 50% непрозрачностью */
background: oklch(from var(--brand) l c h / 0.5);

/* Полностью непрозрачная версия цвета с возможной прозрачностью */
color: oklch(from var(--text-muted) l c h / 1);

/* Масштабирование существующей альфы — если исходный имеет 0.8, снизить до ~0.4 */
background: oklch(from var(--overlay) l c h / calc(alpha * 0.5));

Создание тинтов и шейдов в чистом CSS

Традиционный подход к цветовым шкалам требует предварительного вычисления каждого оттенка и сохранения его как переменной. С синтаксисом относительных цветов можно сгенерировать целую шкалу из одной базовой переменной:

:root {
  --primary: oklch(0.58 0.20 250);

  /* Шкала — предварительные вычисления не нужны */
  --primary-50:  oklch(from var(--primary) 0.97 calc(c * 0.1) h);
  --primary-100: oklch(from var(--primary) 0.94 calc(c * 0.2) h);
  --primary-200: oklch(from var(--primary) 0.88 calc(c * 0.4) h);
  --primary-300: oklch(from var(--primary) 0.78 calc(c * 0.6) h);
  --primary-400: oklch(from var(--primary) 0.68 calc(c * 0.8) h);
  --primary-500: var(--primary);
  --primary-600: oklch(from var(--primary) calc(l - 0.08) c h);
  --primary-700: oklch(from var(--primary) calc(l - 0.16) c h);
  --primary-800: oklch(from var(--primary) calc(l - 0.24) c h);
  --primary-900: oklch(from var(--primary) calc(l - 0.32) c h);
  --primary-950: oklch(from var(--primary) calc(l - 0.38) c h);
}

Измените --primary на любой цвет — и вся 11-шаговая шкала автоматически пересчитается в браузере. Никакого этапа сборки, JavaScript и Sass.

Для производственных дизайн-систем, требующих очень точных перцептуальных шагов, Генератор оттенков предоставляет вручную настроенные шкалы 50–950. Подход с относительными цветами идеален для небольших компонентов или быстрого прототипирования.

Доступные тинты для фонов

Распространённый паттерн — создание очень светлых тинтованных фонов для баннеров уведомлений:

:root {
  --success: oklch(0.65 0.20 145);  /* Насыщенный зелёный */
  --warning: oklch(0.75 0.18 70);   /* Тёплый янтарный */
  --danger:  oklch(0.62 0.24 25);   /* Насыщенный красный */
}

.alert-success {
  background: oklch(from var(--success) 0.96 0.04 h);
  border-left: 3px solid var(--success);
  color: oklch(from var(--success) 0.30 0.14 h);
}

.alert-warning {
  background: oklch(from var(--warning) 0.97 0.04 h);
  border-left: 3px solid var(--warning);
  color: oklch(from var(--warning) 0.35 0.14 h);
}

.alert-danger {
  background: oklch(from var(--danger) 0.96 0.04 h);
  border-left: 3px solid var(--danger);
  color: oklch(from var(--danger) 0.32 0.14 h);
}

Фон — очень светлая, малохроматичная версия цвета предупреждения. Текст использует очень тёмную, умеренно насыщенную версию. Оттенок (h) во всех случаях сохраняется от исходного — всё остаётся в пределах одного оттенка автоматически.

Примеры из реальной жизни с OKLCH

Адаптивные состояния наведения для тем

.card {
  --card-accent: oklch(0.60 0.18 260);
  background: var(--card-accent);
  transition: background-color 150ms ease;
}

.card:hover {
  /* Немного темнее при наведении — работает независимо от акцента */
  background: oklch(from var(--card-accent) calc(l - 0.06) c h);
}

Текст на цветных фонах

.chip {
  --chip-color: oklch(0.62 0.20 260);

  /* Фон: очень светлый тинт */
  background: oklch(from var(--chip-color) 0.94 0.06 h);

  /* Текст: очень тёмная версия того же оттенка */
  color: oklch(from var(--chip-color) 0.28 0.16 h);

  /* Рамка: средне-светлая версия */
  border: 1px solid oklch(from var(--chip-color) 0.78 0.12 h);
}

Адаптация к тёмному режиму с from currentColor

.icon-wrapper {
  /* Цвет иконки наследуется от текстового контекста */
  color: var(--color-text-primary);
}

.icon-wrapper:hover {
  /* Немного темнее текущего цвета иконки */
  color: oklch(from currentColor calc(l - 0.08) c h);
}

.icon-wrapper .background-glow {
  /* Полупрозрачная версия для эффекта свечения */
  background: oklch(from currentColor l c h / 0.15);
}

Генерация комплементарного акцента

:root {
  --brand: oklch(0.60 0.20 250);   /* Синий */

  /* Комплемент: противоположный оттенок, та же светлота и хроматичность */
  --accent: oklch(from var(--brand) l c calc(h + 180));
  /* Результат: примерно оранжевый при оттенке ~70° */

  /* Более мягкий комплемент для фонов */
  --accent-bg: oklch(from var(--brand) 0.95 0.06 calc(h + 180));
}

Поддержка браузерами и резервные варианты

Синтаксис относительных цветов поддерживается в:

  • Chrome/Edge: с версии 119 (ноябрь 2023)
  • Firefox: с версии 128 (июль 2024)
  • Safari: с версии 16.4 (март 2023) — Safari реализовал первым

Глобальная поддержка составляет около 85–88% по состоянию на начало 2026 года. Для более широкого охвата предоставляйте резервные варианты:

.btn-hover {
  /* Запасной вариант: предварительно вычисленный hex для старых браузеров */
  background-color: #1D4ED8;
}

@supports (color: oklch(from red l c h)) {
  .btn-hover {
    /* Современный: динамически производный от базового */
    background-color: oklch(from var(--btn-bg) calc(l - 0.08) c h);
  }
}

Тест @supports (color: oklch(from red l c h)) проверяет именно поддержку синтаксиса относительных цветов, а не просто OKLCH, что важно, поскольку они появились в разных версиях браузеров.

Ключевые выводы

  • Синтаксис относительных цветов использует from <origin-color> внутри любой CSS-функции цвета для разложения цвета на каналы, которые затем можно модифицировать с помощью calc() и скомпоновать в новый цвет.
  • OKLCH — лучшая функция для относительных манипуляций с цветом, поскольку её каналы (светлота, хроматичность, оттенок) соответствуют дизайнерскому замыслу, а светлота перцептуально равномерна — одинаковые инкременты дают одинаково выглядящие изменения.
  • Можно независимо регулировать любой канал: прибавлять к l для осветления, умножать c для обесцвечивания, прибавлять к h для сдвига оттенка, изменять alpha для прозрачности.
  • Исходник from currentColor создаёт самоадаптирующиеся компоненты, производящие цвета из унаследованного цвета текста — автоматически корректные в любом контексте, включая тёмный режим.
  • Поддержка всех современных браузеров с конца 2023/середины 2024 года. Используйте @supports (color: oklch(from red l c h)) для проверки поддержки именно синтаксиса относительных цветов.
  • Используйте Генератор оттенков для точных, вручную настроенных шкал 50–950 в производственных дизайн-системах. Используйте синтаксис относительных цветов для динамических, во время выполнения производных вариантов в компонентах.
  • Используйте Конвертер цветов для перевода существующих hex-цветов бренда в OKLCH, чтобы понять их каналы l, c и h перед написанием выражений с относительными цветами.

Похожие цвета

Похожие бренды

Похожие инструменты