Считайте HWB моделью редактирования sRGB
HWB означает hue, whiteness и blackness. CSS Color 4 определяет его как ещё один способ задать цвет sRGB: берётся полностью насыщенный sRGB-hue, к нему добавляется доля белого, а ещё одна доля резервируется под чёрный. Результат остаётся внутри sRGB, поэтому HWB не открывает Display P3 и другие широкие gamut. Польза модели практическая: color picker сохраняет hue, пока человек регулирует вклад белого и чёрного краёв диапазона.
- Hue использует тот же круг, что HSL, включая визуально неравномерные расстояния между числовыми углами.
- Whiteness поднимает минимальный канал sRGB и ведёт результат к белому, не меняя непрозрачность.
- Blackness снижает максимальный доступный канал и ведёт результат к чёрному, не меняя непрозрачность.
- HWB приводится к sRGB, поэтому любой непрозрачный результат можно представить эквивалентным HEX или rgb().
- Координаты HWB — регуляторы, а не доказательство доступности; контраст считается по итоговым отображаемым цветам.
Используйте синтаксис с пробелами и отдельным alpha
Функция записывается как hwb(H W B / A). Hue принимает угол или число без единицы, которое интерпретируется в градусах; значения за пределами одного оборота зацикливаются. Whiteness и blackness понятнее всего задавать процентами. Alpha размещается после косой черты и без явного значения равен 100%. В отличие от hsl(), у HWB нет старой формы с запятыми: запятые внутри hwb() делают значение невалидным. Современный CSS также разрешает none для отсутствующего компонента, но none не означает ноль и важен прежде всего при интерполяции.
:root {
--action: hwb(210 10% 20%);
--action-translucent: hwb(210 10% 20% / 60%);
--action-wrapped-hue: hwb(570deg 10% 20%); /* Тот же hue, что 210deg */
}
/* Невалидно: у HWB нет синтаксиса с запятыми. */
.invalid-example {
color: hwb(210, 10%, 20%);
}| Запись HWB | Итоговый HEX | Итоговый RGB | Что показывает пример |
|---|---|---|---|
| hwb(0 0% 0%) | #FF0000 | 255 0 0 | Чистый красный hue |
| hwb(120 0% 0%) | #00FF00 | 0 255 0 | Чистый зелёный hue |
| hwb(240 0% 0%) | #0000FF | 0 0 255 | Чистый синий hue |
| hwb(210 10% 20%) | #1A73CC | 26 115 204 | Белый и чёрный добавлены к базовому hue |
| hwb(570 10% 20%) | #1A73CC | 26 115 204 | Hue зацикливается через 360 градусов |
Увеличивайте whiteness и следите за порогом foreground
Зафиксируем hue на 210 градусах и blackness на 20%, после чего увеличим whiteness. Максимальный итоговый канал остаётся на 80%, а меньшие каналы растут. Таблица использует алгоритм HWB-to-sRGB из CSS Color 4, округляет каждый канал до ближайшего 8-битного значения и считает контраст полученного HEX по формуле относительной яркости WCAG. Уровень AA для обычного текста требует не менее 4,5:1.
| HWB | 8-битный sRGB | Чёрный текст | Белый текст | Выбор AA для обычного текста |
|---|---|---|---|---|
| hwb(210 0% 20%) | #0066CC | 3,77:1 | 5,57:1 | Белый |
| hwb(210 10% 20%) | #1A73CC | 4,37:1 | 4,81:1 | Белый |
| hwb(210 20% 20%) | #3380CC | 5,10:1 | 4,12:1 | Чёрный |
| hwb(210 30% 20%) | #4D8CCC | 5,94:1 | 3,54:1 | Чёрный |
| hwb(210 40% 20%) | #6699CC | 6,99:1 | 3,00:1 | Чёрный |
| hwb(210 60% 20%) | #99B3CC | 9,67:1 | 2,17:1 | Чёрный |
- В этой конкретной шкале foreground меняется между whiteness 10% и 20%.
- При whiteness 10% чёрный даёт только 4,37:1, а белый — 4,81:1; округлённый входной процент не делает оба варианта безопасными.
- На шаге 40% чёрный получает 6,99:1: это уровень AA, но значение чуть ниже порога AAA 7:1 для обычного текста.
- Проверяйте каждое семантическое состояние отдельно: один foreground нельзя автоматически переносить на всю HWB-шкалу.
- Сохраняйте неокруглённые коэффициенты для решения pass/fail, а округляйте только показанное число.
Увеличивайте blackness, не смешивая его с opacity
Теперь оставим hue 210 градусов и whiteness 10%. Рост blackness уменьшает доступный вклад чистого hue, а минимальный канал остаётся около 10%. Все строки по-прежнему полностью непрозрачны. Это принципиально отличается от снижения alpha: полупрозрачный цвет показывает неизвестный фон, а HWB с повышенной blackness уже разрешается в полный триплет sRGB. По мере затемнения foreground меняется в обратном направлении.
| HWB | 8-битный sRGB | Чёрный текст | Белый текст | Выбор AA для обычного текста |
|---|---|---|---|---|
| hwb(210 10% 0%) | #1A8CFF | 6,24:1 | 3,37:1 | Чёрный |
| hwb(210 10% 10%) | #1A80E6 | 5,27:1 | 3,98:1 | Чёрный |
| hwb(210 10% 20%) | #1A73CC | 4,37:1 | 4,81:1 | Белый |
| hwb(210 10% 30%) | #1A66B3 | 3,60:1 | 5,84:1 | Белый |
| hwb(210 10% 40%) | #1A5999 | 2,93:1 | 7,16:1 | Белый |
| hwb(210 10% 50%) | #1A4D80 | 2,42:1 | 8,69:1 | Белый |
| hwb(210 10% 60%) | #1A4066 | 1,97:1 | 10,66:1 | Белый |
Нормализуйте whiteness и blackness при сумме 100%
Главный edge case HWB возникает при W + B не меньше 100%. CSS не отклоняет цвет, а делит обе доли на их сумму и возвращает ахроматический результат, у которого все три канала sRGB равны W / (W + B). Исходный hue не способен изменить этот серый и становится powerless. Поэтому значения с разными суммами, но одинаковым отношением W:B после пересечения границы могут дать один цвет.
| Запись HWB | W + B | Нормализованные W:B | Итоговый HEX | Результат hue |
|---|---|---|---|---|
| hwb(45 40% 80%) | 120% | 33,33% : 66,67% | #555555 | Не влияет |
| hwb(200 50% 50%) | 100% | 50% : 50% | #808080 | Не влияет |
| hwb(10 100% 100%) | 200% | 50% : 50% | #808080 | Не влияет |
| hwb(0 70% 70%) | 140% | 50% : 50% | #808080 | Не влияет |
| hwb(320 80% 20%) | 100% | 80% : 20% | #CCCCCC | Не влияет |
- Первая строка — пример нормализации из CSS Color 4: 40 / (40 + 80) даёт серый с уровнем одной трети.
- Равные whiteness и blackness после достижения границы всегда нормализуются в 50-процентный серый.
- Не кодируйте семантический hue в ахроматическом токене: изменение угла не меняет отображаемый результат.
- Если сгенерированная шкала должна сохранять hue, проверяйте W + B < 100% до публикации.
- Избегайте повторных преобразований через округлённые проценты HWB: рядом с границей отношение W:B может дрейфовать.
Преобразуйте RGB, HWB и HSL без потери источника
Для цвета sRGB whiteness в HWB равна наименьшему нормализованному RGB-каналу, а blackness — единице минус наибольший канал. Hue выводится из разницы каналов по той же геометрии, что в HSL. Преобразование детерминировано, но удобное для показа округление необратимо. Храните одно каноническое представление с достаточной точностью, а остальные формы создавайте для документации и copy-кнопок, не перезаписывая ими источник.
| HEX | RGB | Производный HWB | Производный HSL | Примечание |
|---|---|---|---|---|
| #663399 | 102 51 153 | hwb(270 20% 40%) | hsl(270 50% 40%) | Точные целые проценты |
| #FFA500 | 255 165 0 | hwb(38,82 0% 0%) | hsl(38,82 100% 50%) | Чистый HWB-hue с дробным углом |
| #00FFFF | 0 255 255 | hwb(180 0% 0%) | hsl(180 100% 50%) | Чистый циановый hue |
| #808080 | 128 128 128 | hwb(none 50,20% 49,80%) | hsl(none 0% 50,20%) | Hue не влияет |
| #4F46E5 | 79 70 229 | hwb(243,40 27,45% 10,20%) | hsl(243,40 75,35% 58,63%) | Сохраняйте дроби для воспроизводимого аудита |
Публикуйте HWB-токены с проверяемым результатом
Практичный набор HWB-токенов хранит редактируемые координаты, разрешённый sRGB-fallback и проверенные foreground рядом. В прямых CSS-свойствах можно поставить HEX первым, а HWB вторым: ПО, не понимающее позднее значение, сохранит предыдущую декларацию. Такой fallback не решает контраст alpha и не делает непроверенную шкалу доступной — каждому итоговому состоянию всё равно нужны собственные данные.
:root {
--action: hwb(210 10% 20%);
--action-muted: hwb(210 30% 20%);
--action-dark: hwb(210 10% 40%);
--on-action: #FFFFFF;
--on-action-muted: #000000;
}
.action {
color: #FFFFFF;
background: #1A73CC;
background: var(--action); /* 4,81:1 с белым */
}
.action-muted {
color: var(--on-action-muted);
background: #4D8CCC;
background: var(--action-muted); /* 5,94:1 с чёрным */
}- Держите W + B ниже 100%, если выбранный hue должен оставаться видимым.
- Храните канонические координаты HWB с достаточной точностью, а округлённый HEX экспортируйте как производное значение sRGB.
- Отдельно тестируйте normal, hover, active, selected, focus, disabled, светлую и тёмную темы.
- Перед расчётом яркости и контраста скомпозируйте alpha с реальным фоном.
- Не называйте HWB широкогамутным или перцептивно равномерным: он наследует gamut и ограничения hue от sRGB.
- Используйте HSL, когда нужны saturation и модельная lightness, а OKLCH — когда требуется перцептивная шкала.
- Ссылайтесь на спецификацию преобразования и храните неокруглённые значения аудита для воспроизводимости генератора.
Первоисточники
Фактические утверждения статьи проверены по этим опубликованным спецификациям.