OKLCH и современные цвета CSS — почему ваша палитра выглядит неправильно в некоторых браузерах
RGB и HSL были разработаны для мониторов на катодных люминесцентных экранах. Вот почему OKLCH исправляет перцептуальную однородность, как цвет-микс() изменяет смешивание градиентов и что относительный синтаксис цвета открывает без предобработчика.
Вы выбираете синий для основного кнопки. Он выглядит правильно в вашем браузере. Вы открываете стадию на новом MacBook Pro и он выглядит... нормально — просто немного плоским. Ваш дизайнер отправляет скриншот с iPhone, и та же кнопка выглядит значительно ярче. Тот же шестнадцатеричный код. Разные дисплеи.
Это разрыв P3. И на самом деле это наименее интересная часть того, почему цветовая модель CSS, которую вы используете, не срабатывает. Большая проблема — это математика в HSL.
Предел sRGB
Каждый шестнадцатеричный цвет и rgb() значение, которое вы когда-либо писали, живет в пространстве цветов sRGB — стандарте, введенном в 1996 году для мониторов с катушками. Пространство sRGB охватывает примерно 35% цветов, видимых человеческим глазом. Пространство P3, используемое на каждом iPhone с 2017 года и большинстве MacBooks с 2016 года, охватывает около 45%.
Когда вы пишете #3b82f6, этот цвет ограничивается sRGB. На дисплее P3 теоретически может быть отображен более насыщенный синий — но ваш CSS не просит этого. Вы оставляете возможности дисплея без использования по умолчанию.
Чтобы получить цвета P3 напрямую, вы должны использовать color(display-p3 0.2 0.4 0.9). Это работает. Но это не то, почему важно OKLCH. Большая неудача — в фундаментальном предположении HSL.
Светлота HSL — это ложь
HSL была реальным улучшением по сравнению с шестнадцатеричными значениями. Цвет, насыщенность, светлота — концептуально логичные, редактируемые человеком. Проблема: «L» не означает то, что вы думаете.
Поставьте жёлтый на hsl(60, 100%, 50%) и синий на hsl(240, 100%, 50%) рядом. Оба находятся ровно на 50% светлоты.
.yellow { background: hsl(60, 100%, 50%); }
.blue { background: hsl(240, 100%, 50%); }
Жёлтый выглядит почти белым. Синий выглядит серым. Они не близки по восприятию яркости. Это неоднородность восприятия HSL — ось L не отражает то, как человеческое зрение воспринимает яркость.
Это создает реальную проблему при создании шкал цветов. Если вы генерируете 9-шаговую шкалу, шагая по значениям L в HSL, ваши жёлтые и синие цвета выглядят перегруженными, а ваши синие и фиолетовые — мутными. Вам приходится вручную корректировать значения, что полностью уничтожает смысл системного подхода.
OKLCH: разработан для восприятия
OKLCH был разработан Бьёрном Оттоссоном в 2020 году. Он основан на CIELAB (перцептуальном пространстве цветов из 1970-х), но исправляет известные сдвиги по оттенкам — особенно проблему с фиолетовым и синим, где изменение насыщенности вызывает визуальный сдвиг оттенка.
Три канала:
- L (светлота) — от 0 до 1, перцептуально равномерный. L 0.5 в жёлтом выглядит так же ярко, как и L 0.5 в синем. На самом деле.
- C (насыщенность) — начинается с 0 (серый), увеличивается до примерно 0.3–0.4 для сильно насыщенных цветов. Нет фиксированного максимума — верхний предел варьируется в зависимости от оттенка и целевого гамма.
- Н (Цветовой тон) — от 0 до 360 градусов, примерно аналогично оттенку в HSL.
Вот Tailwind blue-500 в обоих системах:
/* sRGB hex */
background: #3b82f6;
/* OKLCH equivalent — same color, different notation */
background: oklch(0.623 0.214 259.1);
/* Push chroma past sRGB — more vivid blue on P3 displays, clips gracefully on sRGB */
background: oklch(0.623 0.27 259.1);
Последнее значение выходит за пределы гаммы sRGB. Браузеры на дисплеях с поддержкой P3 отображают более яркий вариант; старые браузеры ограничивают до ближайшего эквивалента в sRGB. Прогрессивное улучшение без усилий.
color-mix() и почему пространство цветов меняет смешивание
color-mix() была выпущена в Chrome 111, Firefox 113 и Safari 16.2. Она смешивает два цвета в определённом соотношении — достаточно просто. Но пространство цветов, которое вы указываете, значительно меняет результат.
/* Mixes through sRGB — midpoint is a washed-out brown-grey */
background: color-mix(in srgb, oklch(0.7 0.2 30), oklch(0.7 0.2 270));
/* Mixes through the OKLCH color wheel — midpoint is a vivid purple */
background: color-mix(in oklch, oklch(0.7 0.2 30), oklch(0.7 0.2 270));
Когда вы смешиваете оранжевый и синий в sRGB, вы усредняете значения каналов. Средняя точка проходит через десатурированный бурый. В OKLCH вы интерполируете по цветовому кругу — вы попадаете на яркий фиолетовый. То, что правильно, зависит от намерений, но для переходов в интерфейсе, градиентов и состояний hover OKLCH интерполяция почти всегда является желаемой.
Практическое применение: генерация состояния "отключено" без необходимости прописывать второй шестнадцатеричный код.
.button--disabled {
background: color-mix(in oklch, var(--color-primary) 40%, white);
cursor: not-allowed;
}
Синтаксис относительных цветов
Синтаксис относительных цветов (Chrome 119+, Firefox 128+, Safari 16.4+) позволяет производить новый цвет, изменяя отдельные каналы существующего:
:root {
--brand: oklch(0.623 0.214 259.1);
}
.button:hover {
/* Lighten by 8% lightness units */
background: oklch(from var(--brand) calc(l + 0.08) c h);
}
.button:active {
/* Darken and reduce chroma slightly */
background: oklch(from var(--brand) calc(l - 0.08) calc(c - 0.02) h);
}
.button--muted {
/* Drop chroma to near-zero: perceptual grey at the same lightness */
background: oklch(from var(--brand) l 0.03 h);
}
Это заменяет Sass’ lighten(), darken()и desaturate() на встроенный CSS — без препроцессора, без этапа сборки, без необходимости синхронизировать параллельные шестнадцатеричные значения. И поскольку вы работаете в OKLCH, «осветление» действительно выглядит светлее для каждого оттенка в вашей палитре, а не только для некоторых из них.
Одна реальная ограниченность: сложные ограничения каналов (например, ограничение насыщенности для сохранения в гамме) требуют длинных цепочек calc() , которые быстро становятся сложными. Для простых изменений яркости и насыщенности синтаксис чистый. Для более сложных случаев более удобно вычислять значения на этапе сборки и генерировать CSS-свойства.
Поддержка браузеров в 2026 году
| Особенность | Chrome | Firefox | Safari |
|---|---|---|---|
oklch() | 111+ | 113+ | 15.4+ |
color-mix() | 111+ | 113+ | 16.2+ |
| Синтаксис относительных цветов | 119+ | 128+ | 16.4+ |
color(display-p3) | 111+ | 113+ | 10+ |
Глобальная поддержка oklch() превышает 90% к середине 2026 года. Остаются старые браузеры на базе Chromium и любые версии Firefox ниже 113. Если они входят в вашу аудиторию, вам нужно всего лишь два строки фиксации:
.button {
background: #3b82f6; /* sRGB fallback */
}
@supports (background: oklch(0 0 0)) {
.button {
background: oklch(0.623 0.214 259.1);
}
}
На практике: если ваш анализ подтверждает Chrome 111+, Firefox 113+ и Safari 15.4+, вы можете полностью пропустить фиксацию. Упаковка @supports предназначена для спокойствия в внутренних инструментах, где вы не контролируете версии браузеров.
Перевод вашей существующей палитры
Точка сопротивления при внедрении OKLCH — переход от ваших текущих шестнадцатеричных значений к координатам OKLCH и понимание того, что означают каналы для каждого цвета. Утилита Конвертер универсальных цветовых пространств обрабатывает перевод в обе стороны — вставьте шестнадцатеричное или значение HSL, получите OKLCH, затем начните корректировать L и C с реальной точки отсчёта. Поддерживает HSL, RGB, Lab, LCH, HSV и OKLCH в одном месте, что полезно, когда вы работаете с файлом Figma, который предоставляет шестнадцатеричные значения, и хотите получить значения OKLCH, которые можно логически анализировать.
Как на самом деле перейти
Вы не обязаны переписывать всё сразу. Практическая последовательность:
- Начните с интерактивных цветов — ваши основные, вторичные и разрушительные токены. Эти цвета вы уже генерируете в состоянии hover, active и disabled. OKLCH и синтаксис относительных цветов немедленно заменяют эту логику на встроенном CSS.
- Оставьте статические цвета в шестнадцатеричном формате на данный момент — текст, фон, границы. Они не подвергаются программному изменению, поэтому пока нет выгоды от их преобразования.
- Создайте следующую систему с нуля в OKLCH — именно там, где преимущества перцептуальной равномерности становятся структурными. Шаг 500 вашей нейтральной шкалы действительно будет находиться в визуальном центре, а насыщенные оттенки будут одинаковыми по всем оттенкам без ручной настройки.
Цель не в том, чтобы использовать OKLCH ради этого. Цель — иметь систему цветов, в которой математика соответствует тому, что видит ваш глаз — так что вы перестанете компенсировать каждый раз, когда нужно чуть светлее синий.
Установите наши расширения
Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска
恵 Табло результатов прибыло!
Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!
Подписаться на новости
все Новые поступления
всеОбновлять: Наш последний инструмент Был добавлен 13 Июня 2026
