Цветовая модель HSL
(тон, насыщенность, светлота) даёт разработчикам куда более понятный способ работы с цветом в CSS по сравнению с RGB. Вместо того чтобы угадывать, какое сочетание красного, зелёного и синего даст нужный оттенок, HSL позволяет описывать цвет так, как ты о нём думаешь: выбрать цвет, задать его яркость, а потом решить, насколько светлым или тёмным он должен быть. Именно этот сдвиг в мышлении объясняет, почему всё больше разработчиков отказываются от
rgb()
в пользу
hsl()
.
Содержание
RGB vs HSL - Ключевое отличие
RGB задаёт цвет путём смешения трёх световых каналов: красного, зелёного и синего, каждый из которых принимает значения от 0 до 255. Проблема в том, что это способ отображения пикселей на экране, а не то, как человек воспринимает цвет. Хочешь сделать синий чуть светлее в RGB - придётся увеличить все три канала в точной пропорции. Никакого единственного параметра, который можно просто подкрутить, нет.
HSL напрямую отражает то, как люди описывают цвет в обычной речи:
- Тон (Hue) - сам цвет, выраженный в градусах на цветовом круге из 360 градусов. Красный - 0, зелёный - 120, синий - 240.
- Насыщенность (Saturation) - насколько цвет яркий или блёклый: от 0% (чистый серый) до 100% (максимально насыщенный).
- Светлота (Lightness) - насколько цвет светлый или тёмный: от 0% (чёрный) до 100% (белый), при этом 50% - «чистый» цвет.
Вот один и тот же средне-синий цвет в обоих форматах:
/* RGB - what do these numbers even mean at a glance? */
color: rgb(70, 130, 180);
/* HSL - instantly readable: blue hue, moderate saturation, medium lightness */
color: hsl(207, 44%, 49%);
Оба варианта дают стально-синий цвет. Но только HSL-версия говорит тебе что-то полезное с первого взгляда. Тон - 207 (синеватый), насыщенность умеренная - 44%, светлота посередине - 49%. Можно рассуждать о цвете без открытого палитрового инструмента.
| Свойство | RGB | HSL |
|---|---|---|
| Читаемость для человека | Редко | Да |
| Осветлить/затемнить цвет | Менять 3 значения | Менять только светлоту |
| Изменить насыщенность | Пересчитывать все 3 | Менять только насыщенность |
| Создать цветовую палитру | Методом проб и ошибок | Поворот тона на градусы |
| Темизация с CSS-переменными | Громоздко | Чисто и предсказуемо |
Синтаксис HSL в CSS
CSS-функция
hsl()
поддерживается начиная с CSS3. Современный синтаксис (CSS Color Level 4) также позволяет передавать четвёртый параметр прозрачности прямо внутрь
hsl()
, что делает
hsla()
в большинстве случаев избыточным:
/* Classic syntax */
color: hsl(207, 44%, 49%);
/* With alpha (transparency) - old way */
color: hsla(207, 44%, 49%, 0.8);
/* Modern CSS Color Level 4 syntax - commas optional, alpha with slash */
color: hsl(207 44% 49%);
color: hsl(207 44% 49% / 0.8);
color: hsl(207 44% 49% / 80%);
Все основные браузеры поддерживают оба синтаксиса. Синтаксис без запятых - это направление, в котором движется CSS, но вариант с запятыми работает везде, включая Internet Explorer 9+.
Почему HSL выигрывает в UI-разработке
Настоящая сила HSL проявляется в тот момент, когда нужно генерировать вариации цвета - а в UI-разработке это происходит постоянно.
Создание цветовой палитры за считанные секунды
Допустим, фирменный цвет твоего проекта - насыщенный зелёный
hsl(140, 70%, 45%)
. Тебе нужны состояние при наведении, отключённое состояние и светлый фоновый оттенок. В HSL каждый раз меняется только одно значение:
--color-base: hsl(140, 70%, 45%); /* base green */
--color-hover: hsl(140, 70%, 38%); /* darker - just lower lightness */
--color-disabled: hsl(140, 20%, 65%); /* washed out - lower saturation */
--color-tint: hsl(140, 70%, 92%); /* very light background tint */
Попробуй сделать то же самое предсказуемо в RGB без открытого палитрового инструмента. Это реально сложно, потому что нет изолированной оси для изменений.
Аналогичные и дополнительные цвета
Поскольку тон - это градус на цветовом круге, создание гармоничных палитр превращается в арифметику. Аналогичные цвета находятся в пределах 30 градусов друг от друга. Дополнительные (комплементарные) цвета отстоят на 180 градусов:
--primary: hsl(210, 80%, 50%); /* blue */
--analogous-1: hsl(180, 80%, 50%); /* cyan - 30 degrees left */
--analogous-2: hsl(240, 80%, 50%); /* purple - 30 degrees right */
--complementary: hsl(30, 80%, 50%); /* orange - 180 degrees opposite */
Насыщенность и светлота остаются одинаковыми, поэтому цвета воспринимаются как единое семейство. Именно так дизайн-системы вроде Tailwind CSS и Material Design программно генерируют свои цветовые шкалы.
Практические примеры CSS
Кастомные CSS-свойства с компонентами HSL
Один из самых мощных паттернов с HSL - разбить три значения на отдельные CSS-кастомные свойства. Это позволяет собирать цвет в любом месте и менять отдельные каналы на лету:
:root {
--brand-h: 210;
--brand-s: 80%;
--brand-l: 50%;
--brand-color: hsl(var(--brand-h), var(--brand-s), var(--brand-l));
}
.button {
background-color: var(--brand-color);
}
.button:hover {
/* Just override lightness - no need to redefine the whole color */
background-color: hsl(var(--brand-h), var(--brand-s), 40%);
}
.button:disabled {
background-color: hsl(var(--brand-h), 20%, 70%);
}
hsl()
нужны запятые:
hsl(var(--h), var(--s), var(--l))
. Современный синтаксис без запятых пока не работает с
var()
внутри
hsl()
во всех браузерах.
Генерация полной тональной шкалы
Дизайн-системы часто требуют 9-10 оттенков одного цвета (как шкала Tailwind от 50 до 950). С HSL можно сгенерировать всю шкалу, просто увеличивая светлоту с равным шагом, сохраняя тон и насыщенность неизменными:
:root {
--blue-50: hsl(210, 80%, 95%);
--blue-100: hsl(210, 80%, 87%);
--blue-200: hsl(210, 80%, 76%);
--blue-300: hsl(210, 80%, 65%);
--blue-400: hsl(210, 80%, 55%);
--blue-500: hsl(210, 80%, 50%); /* base */
--blue-600: hsl(210, 80%, 43%);
--blue-700: hsl(210, 80%, 36%);
--blue-800: hsl(210, 80%, 26%);
--blue-900: hsl(210, 80%, 16%);
}
Если хочешь подробнее разобраться в том, как форматы цвета соотносятся друг с другом, в руководстве по конвертации HEX в RGB рассмотрена полная картина форматов цвета в CSS, включая ситуации, когда каждый из них является правильным инструментом.
Состояния hover, темизация и тёмная тема
Состояния hover и focus
HSL делает состояния при наведении тривиальными. Вместо того чтобы задавать совершенно отдельный цвет, достаточно просто сдвинуть светлоту:
.btn-primary {
background: hsl(210, 80%, 50%);
transition: background 0.2s ease;
}
.btn-primary:hover { background: hsl(210, 80%, 43%); }
.btn-primary:active { background: hsl(210, 80%, 36%); }
.btn-primary:focus-visible {
outline: 3px solid hsl(210, 80%, 70%);
}
Каждое состояние явно связано с базовым цветом. Коллега, читающий этот код, сразу понимает взаимосвязь между состояниями.
Темизация с HSL-переменными
HSL - это основа современной темизации в CSS. Вынося только тон в переменную, ты позволяешь пользователям или администраторам менять всю цветовую схему приложения, изменив одно число:
/* Default theme: blue */
:root {
--theme-hue: 210;
}
/* Green theme - just swap the hue */
[data-theme="green"] {
--theme-hue: 140;
}
/* Purple theme */
[data-theme="purple"] {
--theme-hue: 270;
}
/* All components use the same hue variable */
.button { background: hsl(var(--theme-hue), 75%, 50%); }
.link { color: hsl(var(--theme-hue), 75%, 40%); }
.badge { background: hsl(var(--theme-hue), 75%, 92%); color: hsl(var(--theme-hue), 75%, 25%); }
.focus-ring { outline-color: hsl(var(--theme-hue), 75%, 65%); }
Тёмная тема с HSL
Тёмная тема - это именно то место, где HSL по-настоящему вырывается вперёд. Вместо того чтобы поддерживать две полностью отдельные цветовые палитры, ты просто инвертируешь значения светлоты в рамках того же тона:
:root {
--bg: hsl(210, 20%, 98%); /* near-white background */
--text: hsl(210, 20%, 15%); /* near-black text */
--card: hsl(210, 20%, 93%); /* slightly darker card */
}
@media (prefers-color-scheme: dark) {
:root {
--bg: hsl(210, 20%, 10%); /* flip: near-black background */
--text: hsl(210, 20%, 90%); /* flip: near-white text */
--card: hsl(210, 20%, 15%); /* slightly lighter card in dark */
}
}
Обрати внимание: тон (210) и насыщенность (20%) не меняются никогда. Инвертируется только светлота. Это позволяет тёмной теме ощущаться как то же самое оформление, просто перевёрнутое - а именно так и должна работать хорошая тёмная тема.
Поддержка браузеров и совместимость
HSL отлично поддерживается браузерами. Функция
hsl()
доступна начиная с:
- Chrome 1 (2008)
- Firefox 1 (2004)
- Safari 3.1 (2008)
- Internet Explorer 9 (2011)
- Edge 12 (2015)
Современный синтаксис без запятых (
hsl(210 80% 50%)
) и синтаксис с прозрачностью через слэш (
hsl(210 80% 50% / 0.5)
) входят в спецификацию
CSS Color Level 4
и поддерживаются во всех современных браузерах начиная с 2023 года. Если тебе нужна поддержка IE11 (что сегодня редкость), придерживайся синтаксиса с запятыми.
hsl()
с запятыми работает в каждом браузере, которым пользуются твои пользователи. Современный синтаксис с пробелами вместо запятых поддерживается в Chrome 90+, Firefox 89+ и Safari 14.1+, что покрывает более 95% мирового использования браузеров.
Ты всегда можешь воспользоваться палитровым инструментом , чтобы конвертировать значения между HSL, RGB и HEX - когда нужно сверить значения или передать цвета в инструменты, принимающие только один формат.
HSL vs OKLCH - Что дальше?
Если хочешь пойти глубже HSL, стоит познакомиться с OKLCH . Это перцептивно равномерное цветовое пространство: одинаковые числовые шаги по светлоте или насыщенности действительно воспринимаются человеческим глазом как одинаковые - чего HSL полностью гарантировать не может.
Проблема HSL в том, что два цвета с одинаковым значением светлоты могут выглядеть совершенно по-разному по воспринимаемой яркости. Например,
hsl(60, 100%, 50%)
(жёлтый) выглядит значительно ярче, чем
hsl(240, 100%, 50%)
(синий), хотя у обоих светлота 50%. OKLCH исправляет этот недостаток.
/* HSL - same lightness, different perceived brightness */
color: hsl(60, 100%, 50%); /* yellow - looks very bright */
color: hsl(240, 100%, 50%); /* blue - looks much darker */
/* OKLCH - same lightness, actually looks the same to the eye */
color: oklch(0.75 0.18 90); /* yellow-ish */
color: oklch(0.75 0.18 260); /* blue-ish - genuinely similar perceived brightness */
OKLCH также поддерживает
цвета широкой гаммы
(P3 display colors), выходящие за пределы диапазона sRGB, которым ограничен HSL. Поддержка
oklch()
в браузерах уверенная в 2024 году: Chrome 111+, Firefox 113+, Safari 15.4+.
Для большинства проектов прямо сейчас HSL - это оптимальный выбор: читаемый, удобный в поддержке, повсеместно поддерживаемый и значительно лучше RGB. OKLCH - правильный выбор, когда ты строишь дизайн-систему с математически согласованными коэффициентами контрастности или хочешь ориентироваться на дисплеи с широкой цветовой гаммой.
Если ты исследуешь цветовые взаимосвязи визуально в процессе создания палитры, инструмент цветового исследования позволяет экспериментировать со значениями HSL и в реальном времени видеть, как взаимодействуют повороты тона, сдвиги насыщенности и изменения светлоты.
Подбирай HSL-цвета без лишних догадок
Наш палитровый инструмент позволяет визуально настраивать тон, насыщенность и светлоту, а затем скопировать готовый HSL-цвет прямо в CSS - никаких вычислений в уме.
Попробовать палитровый инструмент →
Полный рефакторинг не обязателен, но стоит переходить на HSL для любых новых определений цвета, особенно при использовании CSS-кастомных свойств. Наибольший выигрыш ты получишь при построении или поддержке дизайн-системы, создании состояний при наведении или реализации тёмной темы. Смешивать RGB и HSL в одном проекте - совершенно валидный CSS: браузеры обрабатывают оба формата без какой-либо разницы в производительности.
Нет, никакой значимой разницы в производительности нет. Браузер конвертирует все форматы цвета CSS во внутреннее представление на этапе парсинга, поэтому независимо от того, напишешь ли ты
hsl(207, 44%, 49%)
или
rgb(70, 130, 180)
, движок рендеринга после этого шага обрабатывает их одинаково. Выбор формата - исключительно вопрос удобства разработки и удобства поддержки, а не производительности во время выполнения.
Да, и это один из сильнейших сценариев применения HSL в JavaScript. Можно хранить тон, насыщенность и светлоту как отдельные числа, а затем динамически собирать строку цвета:
element.style.color = `hsl(${hue}, ${saturation}%, ${lightness}%)`
. Это делает анимации, переключение тем и интерактивные элементы управления цветом значительно проще в реализации, чем работа с RGB-каналами, где для достижения тех же эффектов потребовалась бы математика конвертации.
HSL (тон, насыщенность, светлота) и HSB/HSV (тон, насыщенность, яркость/значение) - это разные цветовые модели, хотя у них общая ось тона. В HSL светлота 50% даёт чистый, полностью насыщенный цвет. В HSB яркость 100% даёт чистый цвет. При одинаковых значениях насыщенности и яркости/светлоты эти модели дают разные результаты. CSS использует именно HSL - HSB/HSV распространён в инструментах дизайна вроде Photoshop и Figma, но не является нативным форматом CSS.
Конвертация из HEX в HSL проходит через промежуточный шаг RGB: сначала HEX-пары переводятся в значения RGB (0-255), нормализуются до диапазона 0-1, а затем применяется формула конвертации в HSL. На практике большинство разработчиков используют палитровый инструмент, инструмент дизайна вроде Figma или встроенный палитровый инструмент DevTools браузера - это мгновенно, без ручных вычислений. DevTools браузера позволяет кликнуть на любой цветовой образец и переключаться между HEX, RGB и HSL-представлениями.
Да, OKLCH надёжнее для работы с доступностью, поскольку является перцептивно равномерным - одинаковые шаги по каналу светлоты соответствуют одинаковым изменениям воспринимаемой яркости. Это упрощает создание цветовых палитр с предсказуемыми коэффициентами контрастности для разных тонов. В HSL жёлтый с 50% светлоты выглядит значительно ярче, чем синий с 50% светлоты, что может приводить к неожиданным проблемам с доступностью. Для соответствия требованиям контрастности WCAG OKLCH даёт более предсказуемые результаты при создании доступных цветовых шкал.