01

Выбирайте OKLCH, когда его координаты соответствуют задаче

OKLCH — полярная форма Oklab. L описывает воспринимаемую светлоту, C — chroma, а H — угол цветового тона. CSS Color 4 называет Oklab пространством, оптимизированным по визуально похожим цветам, и отмечает более линейное поведение hue, лучшую перцептивную равномерность и оценку chroma по сравнению с CIE LCH. Поэтому OKLCH полезен для связанных токенов, шкал светлоты и интерполяции, которая реже проваливается в тусклый серый центр. Но модель лишь улучшает предсказуемость: каждый шаг всё равно нужно смотреть на реальных дисплеях.

  • Используйте L для более светлых и тёмных ролей, помня, что равные числа лишь приблизительно соответствуют равным визуальным шагам.
  • Используйте C как расстояние от нейтральной оси: рост значения усиливает цветность, пока ограничением не станет выбранный gamut.
  • Используйте H для удержания одной цветовой семьи или явного выбора пути между hue при интерполяции.
  • Не принимайте L, C и H за доказательство доступности. Контраст WCAG считается по относительной яркости итоговых отображаемых sRGB-цветов.
  • Храните вместе с исходным OKLCH целевой gamut и fallback, чтобы токен воспроизводился одинаково в браузерах, дизайн-инструментах и документации.
02

Записывайте синтаксис без ловушки процентов chroma

Современная запись использует пробелы и необязательную косую черту перед alpha: oklch(L C H / A). Запятые недопустимы. Lightness задаётся числом от 0 до 1 или процентами от 0% до 100%. Chroma обычно удобнее записывать числом. По CSS Color 4 её 100% соответствуют 0.4, поэтому 25% означают 0.1, а не 0.25. Единого максимума C для всех цветов нет: практический диапазон доходит примерно до 0.5, а конкретная граница зависит от L, H и целевого gamut. Отрицательная chroma приводится к нулю.

css
:root {
  --brand: oklch(70% 0.16 30);
  --brand-same-chroma: oklch(70% 40% 30); /* 40% от 0.4 = 0.16 */
  --brand-muted: oklch(70% 0.08 30);
  --brand-overlay: oklch(70% 0.16 30 / 65%);
}
КоординатаЗапись CSSПрактический смыслВажное ограничение
L70% или 0.7Координата воспринимаемой светлотыНе равна относительной яркости WCAG
C0.16 или 40%Расстояние от нейтральной оси100% соответствуют 0.4
H30 или 30degПолярный угол hueНе влияет при почти нулевой chroma
A/ 65%Непрозрачность до композицииКонтраст зависит от фона
03

Стройте шкалу светлоты и проверяйте каждый foreground

В этой шкале chroma зафиксирована на 0.08, hue — на 30, а L меняется от 35% до 85%. HEX — это 8-битные приближения sRGB, рассчитанные матрицами Oklab из CSS Color 4 и округлённые до ближайшего значения канала. После этого контраст заново рассчитан для каждого округлённого HEX по формуле относительной яркости WCAG. Уровень AA для обычного текста требует не менее 4,5:1. OKLCH L организует шкалу, но доказательство доступности даёт только итоговый скомпозированный цвет.

OKLCH8-битный sRGBЧёрный текстБелый текстВыбор AA для обычного текста
oklch(35% 0.08 30)#5D28201,79:111,73:1Белый
oklch(45% 0.08 30)#7C433A2,72:17,72:1Белый
oklch(55% 0.08 30)#9B5F554,16:15,05:1Белый
oklch(65% 0.08 30)#BB7D726,29:13,34:1Чёрный
oklch(75% 0.08 30)#DC9B909,13:12,30:1Чёрный
oklch(85% 0.08 30)#FEBBAF12,94:11,62:1Чёрный
  • В этой конкретной шкале foreground меняется между L 55% и L 65%; универсального порога OKLCH lightness нет.
  • При L 55% чёрный не проходит AA для обычного текста, хотя шаг выглядит серединой шкалы: коэффициент равен 4,16:1.
  • Сравнивайте с порогом неокруглённое значение, а округляйте только число в документации.
  • Проверяйте hover, selected, disabled, градиентные и полупрозрачные состояния после композиции всех слоёв.
  • Приближённый HEX полезен для проверки sRGB, но не способен точно сохранить исходный цвет за пределами sRGB.
04

Увеличивайте chroma до границы целевого gamut

У chroma нет одного безопасного максимума для всех палитр. При фиксированных L 70% и H 30 значения до C 0.19 в расчёте ниже остаются в sRGB. Уже C 0.20 выходит за sRGB, но ещё помещается в Display P3; C 0.24 тоже является корректным OKLCH-цветом внутри этого более широкого gamut. При других L или H граница окажется в другом месте. Для значений вне sRGB точного 8-битного HEX не существует: подстановка обрезанного HEX скрыла бы изменение gamut и могла бы сдвинуть hue или lightness.

OKLCH при L 70%, H 308-битное приближение sRGBsRGBDisplay P3Интерпретация
C 0.00#9E9E9EВнутриВнутриНейтральный; hue не влияет
C 0.08#CB8C81ВнутриВнутриПриглушённый цвет
C 0.16#F17260ВнутриВнутриВыразительный цвет sRGB
C 0.19#FE6652ВнутриВнутриРядом с этой границей sRGB
C 0.20СнаружиВнутриНет точного HEX
C 0.24СнаружиВнутриШирокий gamut
05

Разделяйте fallback синтаксиса и gamut mapping

Fallback и gamut mapping решают разные задачи. Первый даёт старому ПО понятную декларацию. Поддерживающий OKLCH браузер способен разобрать запись, но всё равно может преобразовать цвет под gamut дисплея. Для custom property безопаснее использовать @supports: если записать неподдерживаемый цвет только в переменную, сама переменная останется допустимой до подстановки, а использующее её свойство может стать невалидным вместо возврата к предыдущему значению. Условный блок ниже исключает эту ловушку.

css
:root {
  --brand: #FE6652;
}

@supports (color: oklch(70% 0.20 30)) {
  :root {
    --brand: oklch(70% 0.20 30);
  }
}

.button {
  color: #000000;
  background: var(--brand);
}
  • Выбирайте fallback осознанно: #FE6652 здесь является последним шагом внутри sRGB, но не заявлен как точная копия C 0.20.
  • Укажите, нацелен ли основной токен на sRGB, Display P3 или другой gamut, и проверяйте каждую ветку на подходящих дисплеях.
  • Не обрезайте все токены заранее ради одинакового результата инструментов: так теряется широкогамутный источник и нарушается равномерность шкалы.
  • Ожидайте gamut mapping браузера или цветового pipeline на выводе и проверяйте отображённый результат, а не предполагаемый алгоритм.
  • Считайте контраст отдельно для fallback и mapped-версии, а не переносите один коэффициент с исходных координат.
06

Осознанно выбирайте пространство и путь интерполяции

Пространство между endpoint не менее важно, чем запись самих endpoint. CSS-градиенты и color-mix() позволяют запросить интерполяцию в OKLCH. Полярное пространство способно лучше сохранить chroma, чем смешивание прямоугольных каналов через тусклый центр, однако вокруг круга hue существует несколько маршрутов. Shorter и longer дают принципиально разные промежуточные семьи, а increasing и decreasing фиксируют направление. Даже при отображаемых endpoint промежуточный цвет может выйти за gamut, поэтому готовую шкалу всё равно проверяют на gamut и контраст.

css
.spectrum {
  background: linear-gradient(
    90deg in oklch shorter hue,
    oklch(70% 0.16 30),
    oklch(70% 0.16 280)
  );
}

:root {
  --brand-soft: color-mix(
    in oklch,
    oklch(70% 0.16 30) 35%,
    white
  );
}
  • Используйте Oklab для прямой перцептивной интерполяции, а OKLCH — когда важнее полярный путь hue или сохранение chroma.
  • Указывайте shorter, longer, increasing или decreasing, если маршрут меняет смысл продукта; семантическая шкала не должна зависеть от случайного default.
  • Проверяйте промежуточные остановки. Анализ только endpoint не выявит вышедший за gamut или низкоконтрастный центр.
  • Смешивание с белым меняет не только L. Если должна изменяться одна координата, генерируйте явные OKLCH-токены.
  • Используйте один документированный pipeline, чтобы дизайн-превью, CSS, скриншоты и аудиты применяли одинаковые правила интерполяции.
07

Публикуйте OKLCH-токены с проверяемыми данными

Рабочую OKLCH-палитру нужно уметь проверить без восстановления скрытых настроек дизайн-инструмента. Храните исходные координаты с достаточной точностью, называйте целевой gamut, добавляйте осознанный fallback и публикуйте рассчитанные данные рядом с семантическим токеном. Затем тестируйте фактически отображённые состояния. Так перцептивные преимущества модели остаются, а поддержка браузеров, gamut и доступность становятся обычными инженерными входными данными.

css
:root {
  --action-strong: oklch(55% 0.08 30);
  --action: oklch(65% 0.08 30);
  --action-soft: oklch(85% 0.08 30);

  --on-action-strong: #FFFFFF; /* 5,05:1 на #9B5F55 */
  --on-action: #000000;        /* 6,29:1 на #BB7D72 */
  --on-action-soft: #000000;   /* 12,94:1 на #FEBBAF */
}
  • Не смешивайте L с относительной яркостью WCAG, а C — с HSL saturation.
  • Документируйте нормализацию процентов, особенно правило CSS: C 100% равна 0.4.
  • Считайте hue бессильным у нейтральных цветов и не создавайте нестабильные названия по невидимой координате.
  • Отмечайте токены внутри sRGB, токены для широкого gamut и fallback при отсутствии основного пути.
  • Сохраняйте точность для преобразования, но называйте округлённый HEX именно 8-битным приближением sRGB.
  • Проверяйте контраст итоговой композиции: alpha, градиенты, overlay и gamut mapping меняют увиденную пользователем пару.
  • Отдельно проверяйте промежуточные цвета, focus indicator, border, hover, selected, светлую, тёмную и forced-colors темы.
  • Ссылайтесь на спецификацию и метод преобразования, чтобы изменения генератора оставались объяснимыми и воспроизводимыми.
S

Первоисточники

Фактические утверждения статьи проверены по этим опубликованным спецификациям.

  1. W3C CSS Color 4 — обзор Oklab и OkLCh
  2. W3C CSS Color 4 — задание Oklab и OkLCh
  3. W3C CSS Color 4 — преобразование цветового охвата
  4. W3C CSS Color 4 — методы интерполяции цвета
  5. W3C CSS Images 4 — интерполяция цвета в градиентах
  6. W3C CSS Color 5 — color-mix()
  7. W3C CSS Conditional 3 — @supports
  8. W3C WCAG 2.2 — относительная яркость
  9. W3C WCAG 2.2 — контраст (минимальный)