Почему я не перешёл на OKLCH

Решил попробовать новый формат цвета, про который пишут “[лучший формат цвета в CSS](https://htmlbook.ru/blog/oklch-luchshiy-format-dlya-cveta-v-css)” и переводят [хайповые статьи от Evil Martians](https://web-standards.ru/articles/oklch-in-css-why-quit-rgb-hsl/). Что хочу сказать – OKLCH это ад для программиста.

### Чем хорош HSL

В HSL у тебя есть HUE (0 – 360), Saturation (0% – 100%), Lightness (0% – 100%). Это значит, что можно выставить желаемые Saturation и Lightness, а потом крутить HUE и получать примерно схожие цвета по восприятию. Да, они будут не идеальны по восприятию, но это, что называется “close enought”. Зато, у тебя на любое значение Saturation и Lightness есть значение HUE. Когда смотришь на OKLCH, то он изначально выглядит странно. LCH = Lightness (0 – 1 или 0% – 100%), Chroma (~0.4 – 0.5 в зависимости от HUE), HUE (0 – 360). Но проблема даже не в том, что здесь насыщенность (Chroma) имеет плавающее максимальное значение. Основной ад здесь с HUE.
– [!(/wp-content/uploads/2025/08/hsl_dark-1024×755.webp)](/wp-content/uploads/2025/08/hsl_dark.webp)
– [!(/wp-content/uploads/2025/08/hsl_light-1024×758.webp)](/wp-content/uploads/2025/08/hsl_light.webp)
– [!(/wp-content/uploads/2025/08/oklch_dark-1024×753.webp)](/wp-content/uploads/2025/08/oklch_dark.webp)

### Что сделали в OKLCH

По сути, они взяли спектр HSL и начали крутить цвета вверх-вниз, чтобы выровнять всё по восприятию. В итоге, уже не на любое значение насыщенности и яркости у вас есть цвет в HUE. Где-то HUE съехал и там вообще пусто – ну вот просто нет цвета, который воспринимался на ровне с другими цветами на этом уровне. Мы ведь выравниваем всё по восприятию…

### Почему это проблема для программистов

Вот PHP-функция, которая генерирует HUE для строки по спектру:

“`
function simpleHue($str) {
// оставим только латинские буквы
$str = preg_replace(‘/[^a-z]/’, ”, strtolower($str));
$rangeMin = 1;
$rangeMax = 360;

for ($i = 0; $i < strlen($str); $i++) {
$char = $str[$i];
$index = ord($char) – ord(‘a’);

$segmentSize = ($rangeMax – $rangeMin) / 26;
$rangeMin = $rangeMin + $segmentSize * $index;
$rangeMax = $rangeMin + $segmentSize;

// если разница меньше 1 — хватит, результат будет одинаков после округления
if (($rangeMax – $rangeMin) < 1) break;
}

return round(($rangeMin + $rangeMax) / 2);
}
“`

Работает так – берём наш спектр от 1 до 360, задаём каждой букве английского алфавита свой отрезок и смотрим какой отрезок нам нужен по первой букве в строке. Потом этот отрезок опять делим по буквам и получаем более точное значение. Так до тех пор, пока не сократим выборку до целого числа. Таким образом, если взять список каких-то доменов, вывести их столбцом в алфавитном порядке и прогнать через эту функцию, то получится, что они разложены по спектру как по полочкам, в зависимости от первых букв.

Я уже неоднократно пользовался таким приёмом с HSL и результат всегда был более чем приемлемый. Но, с OKLCH это работать не будет. Если мы зайдём на официальный сайт и покрутим там ползунки, то всё увидим наглядно. Побаловавшись с их генератором я определил опытным путём, что если я хочу, чтобы HUE оставался всегда полным, то я не могу поднимать Chroma выше 0.127. И при этом Lightness вообще двигать нельзя, он будет зафиксирован на значении 0.75. Это будет самый насыщенный вариант HUE, который мы можем получить из OKLCH, при этом чтобы HUE оставался полным. Не долго думая, я написал свой калькулятор.

### Что в сухом остатке

В целом, я могу пользоваться OKLCH для своих привычных целей, если меня устраивают пастельные цвета, которыми я ограничен в своём калькуляторе. И если это так, то использовать OKLCH будет даже лучше чем HSL. Но, подгонять что-то в коде вручную уже не получится – надо сначала определиться со значениями Lightness и Chroma через калькулятор, а потом уже крутить HUE в коде как угодно. С CSS та же проблема, как я понимаю. Ты захотел подкрутить в CSS циферку в каком-то цвете вручную, а оказалось, что такого цвета в OKLCH нет. В итоге, надо всегда пользоваться генератором с офф-сайта, чтобы не накосячить.

Работать с OKLCH – это особая форма мазахизма. И я никогда не запихну такое в продакшн без крайней необходимости. Потому что это выглядит как грязь и не понятно как это теперь редактировать, если вдруг понадобится.

“`
:root { /* light theme */
–link-bg-chroma: 0.0369;
–link-bg-light: 0.8335;

–link-color-chroma: 0.055;
–link-color-light: 0.325;

–link-shadow-chroma: 0.0497;
–link-shadow-light: 0.7503;

–body-bg-light: 0.9848;
–body-text-light: 0.21560726514268813;
}

html.dark-theme {
–link-bg-chroma: 0.0312;
–link-bg-light: 0.3904;

–link-color-chroma: 0.0701;
–link-color-light: 0.7857;

–link-shadow-chroma: 0.0312;
–link-shadow-light: 0.3904;

–body-bg-light: 0.193;
–body-text-light: 0.8845;
}
“`

Для сравнения, вот тоже самое на HSL. Тут понятно всё и нет никаких странных ограничений.

“`
:root { /* light theme */
–link-bg-sat: 40%;
–link-bg-light: 80%;

–link-color-sat: 60%;
–link-color-light: 25%;

–link-shadow-sat: 35%;
–link-shadow-light: 70%;

–body-bg-light: 98%;
–body-text-light: 10%;
}

html.dark-theme {
–link-bg-sat: 20%;
–link-bg-light: 28%;

–link-color-sat: 60%;
–link-color-light: 75%;

–link-shadow-sat: 35%;
–link-shadow-light: 30%;

–body-bg-light: 8%;
–body-text-light: 85%;
}
“`

### Сравнительный тест
После конвертации через калькулятор на офф-сайте, цвета у меня не совпадают. Так произошло потому, что я не конвертировал HUE, он у меня генерируется автоматически из приведённой выше PHP-функции. Ну а HUE у HSL и OKLCH, естественно, не совпадают.

– [![Hsl dark](/wp-content/uploads/2025/08/hsl_dark-1024×755.webp){.alignnone}](/wp-content/uploads/2025/08/hsl_dark.webp “myset0_2 “)
– [![Oklch dark](/wp-content/uploads/2025/08/oklch_dark-1024×753.webp){.alignnone1}](/wp-content/uploads/2025/08/oklch_dark.webp “myset0_2 “)
– [![Hsl light](/wp-content/uploads/2025/08/hsl_light-1024×758.webp){.alignnone}](/wp-content/uploads/2025/08/hsl_light.webp “myset0_2 “)
– [![Oklch llight](/wp-content/uploads/2025/08/oklch_llight-1024×753.webp){.alignnone}](/wp-content/uploads/2025/08/oklch_llight.webp “myset0_2 “)