Цвета в CSS: hex, rgb, hsl и oklch на живом примере
Пять способов задать один и тот же цвет в CSS дают разный результат при наведении, в тёмной теме и при расчёте контраста. Разбираем, какой формат выбрать под задачу.

Одну и ту же синюю кнопку можно описать пятью способами: #2563eb, rgb(37 99 235), hsl(221 83% 53%), oklch(55% 0.22 264) или именем royalblue (последнее даст другой оттенок). Визуально они почти совпадают, но как только вы начинаете делать hover-состояние, тёмную тему или проверять контраст — разница между форматами становится решающей. Разбираем на живом примере кнопки: где hex тормозит, а hsl и oklch экономят время. Актуально для CSS в браузерах 2024–2025 годов.
Пять форматов для одного цвета
CSS понимает несколько синтаксисов записи цвета. Вот один и тот же (почти) синий в каждом из них:
/* именованный — фиксированный набор из ~150 слов */
color: royalblue;
/* hex — самый распространённый */
color: #2563eb;
/* rgb — современный синтаксис через пробелы, CSS Color 4 */
color: rgb(37 99 235);
color: rgb(37 99 235 / 0.5); /* с прозрачностью */
/* hsl — тон, насыщенность, светлота */
color: hsl(221 83% 53%);
/* oklch — перцептивно равномерное пространство */
color: oklch(55% 0.22 264);
Старый синтаксис с запятыми (rgb(37, 99, 235) и rgba(...)) по-прежнему работает и его никто не отменял. Новый через пробелы короче и объединяет rgb и rgba в одну функцию — отдельный rgba больше не нужен, хотя и поддерживается.
Что означают числа
- hex — три пары шестнадцатеричных цифр: красный, зелёный, синий от
00доff. Четвёртая пара — альфа:#2563eb80это тот же синий с прозрачностью ~50%. - rgb — те же каналы, но в десятичных числах 0–255.
- hsl — тон (0–360 градусов по кругу), насыщенность и светлота в процентах. Читается человеком: 221 — это синий сектор круга.
- oklch — светлота, насыщенность (chroma) и тон, но в пространстве, где равные шаги воспринимаются глазом как равные. Про это ниже отдельно.
Живой пример: кнопка и её состояния
Задача простая: синяя кнопка, которая при наведении становится темнее, а при нажатии — ещё темнее. На hex это выглядит так:
.btn {
background: #2563eb;
}
.btn:hover {
background: #1d4ed8; /* откуда это число? подобрано на глаз */
}
.btn:active {
background: #1e40af; /* и это тоже */
}
Проблема очевидна: чтобы получить "тот же цвет, но на 10% темнее", вы лезете в пипетку или подбираете hex вручную. Связи между тремя значениями нет — это три независимых магических числа. Если дизайнер попросит сделать кнопку не синей, а зелёной, вы пересчитываете все три.
То же на hsl
.btn {
--hue: 221;
--sat: 83%;
background: hsl(var(--hue) var(--sat) 53%);
}
.btn:hover {
background: hsl(var(--hue) var(--sat) 45%); /* та же логика, меньше светлота */
}
.btn:active {
background: hsl(var(--hue) var(--sat) 38%);
}
Теперь темнее — это буквально "уменьшить светлоту". Смена цвета кнопки на зелёную — это правка одной переменной --hue на 140. Три состояния пересчитываются сами, потому что тон и насыщенность вынесены в переменные.
Проблема hsl, которую видно только на глаз
У hsl есть неприятная особенность: при одинаковой светлоте разные тона воспринимаются по-разному по яркости. Жёлтый hsl(60 100% 50%) кажется гораздо светлее синего hsl(240 100% 50%), хотя формально светлота у обоих 50%. Из-за этого палитра, построенная сдвигом светлоты в hsl, выглядит неровно: одни цвета "проваливаются", другие "выпирают".
oklch: когда светлота честная
Пространство OKLCH решает именно эту проблему. Его светлота (первое число) перцептивно равномерна: oklch(60% ...) для синего и для жёлтого будут выглядеть одинаково яркими. Это делает генерацию палитр предсказуемой.
.btn {
--l: 60%;
--c: 0.2;
--h: 264;
background: oklch(var(--l) var(--c) var(--h));
}
.btn:hover {
background: oklch(52% var(--c) var(--h)); /* минус 8% светлоты */
}
Второе преимущество — доступ к цветам за пределами sRGB. На современных экранах с широким охватом (P3) oklch даёт более сочные цвета, недостижимые в hex. Браузеры без поддержки P3 отрисуют ближайший доступный оттенок.
Если вы строите дизайн-систему с палитрой оттенков (50, 100, 200… 900), oklch экономит часы: шаги светлоты дают ровную лесенку, а не кашу, которую пришлось бы выправлять руками в hex.
Поддержка браузерами
Синтаксис oklch() и rgb() через пробелы работает в актуальных Chrome, Firefox и Safari (примерно с 2023 года). Для старых браузеров дайте hex-запасной вариант первой строкой — CSS применит последнее свойство, которое понимает:
.btn {
background: #2563eb; /* понимают все */
background: oklch(55% 0.22 264); /* современные перезапишут */
}
Проверить актуальную поддержку конкретного значения стоит на caniuse.com — она расширяется от версии к версии.
Сравнение форматов
| Формат | Читаемость | Легко сделать темнее/светлее | Прозрачность | Цвета вне sRGB |
|---|---|---|---|---|
| именованный | высокая | нет | нет | нет |
| hex | низкая | нет | да (8 знаков) | нет |
| rgb | средняя | нет | да | нет |
| hsl | высокая | да, но неравномерно | да | нет |
| oklch | средняя | да, равномерно | да | да (P3) |
Когда что выбирать
- hex — когда цвет один и брать его из макета один в один. Дизайнер прислал
#2563eb— вставили и забыли. - rgb с альфой — когда нужна полупрозрачная накладка поверх фото или блока:
rgb(0 0 0 / 0.4)для затемнения. - hsl — когда нужны варианты одного тона (светлее/темнее для hover) и вам не критична идеальная равномерность.
- oklch — когда строите палитру дизайн-системы или хотите задействовать широкий цветовой охват экранов.
Частые ошибки
- Забыть про контраст. Красивый цвет на кнопке может не проходить порог контраста для текста. Формат записи на контраст не влияет — проверяйте пары "текст/фон" любым чекером на соответствие WCAG.
- Смешать запятые и пробелы. Внутри одной функции синтаксис должен быть одинаковый: либо
rgb(37, 99, 235), либоrgb(37 99 235). Комбинация — синтаксическая ошибка, свойство игнорируется. - Считать, что hsl-светлота = яркость. Как показано выше, это не так. Для ровной палитры берите oklch.
- Хардкодить hex в hover вместо переменной. Три магических числа вместо одной переменной — это три места для правки при смене темы.
Что делать дальше
Возьмите одну кнопку в своём проекте и вынесите её тон и насыщенность в CSS-переменные, а состояния hover/active выразите через изменение только светлоты. Дальше — соберите на этой основе тёмную тему: часто достаточно инвертировать значения светлоты, оставив тон и насыщенность нетронутыми. Для генерации ровной палитры оттенков попробуйте oklch и сравните лесенку светлот с тем, что даёт hsl — разница будет видна сразу.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: CSS Color Module Level 4 — W3C, color value — MDN Web Docs
Частые вопросы
А если браузер пользователя не поддерживает oklch?
Старый синтаксис rgba() и hsla() ещё работает?
Можно ли смешивать цвета прямо в CSS?
Какой формат лучше для доступности и контраста?
Что делать, если hover-цвет в hsl выглядит грязным?
Почему royalblue и #2563eb дают разный оттенок?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.