OKLCH в CSS: изучаем цветовую модель на практических примерах

Пост опубликован в блогах iXBT.com, его автор не имеет отношения к редакции iXBT.com
| Статья | ИИ, сервисы и приложения

Если углубиться в изучение современного CSS, то может голова пойти кругом от обилия цветовых моделей и их особенностей. Зачем появилась еще одна, если многие веб-разработчики по-прежнему используют HEX-коды для работы с цветом? Попробуем выяснить, какие возможности открывает цветовая модель OKLCH.

OKLCH — это относительно новая цветовая модель, учитывающая особенности человеческого зрения, с помощью которой можно предсказуемо управлять цветом, меняя три параметра:

  • L (Lightness / Яркость)
  • C (Chroma / Насыщенность)
  • H (Hue / Оттенок)

Пример:

oklch(0.6 0.2 270)

Можно также задать прозрачность:

oklch(0.6 0.2 270 / 0.5)

Цветовая модель OKLCH поддерживает работу с расширенными цветовыми пространствами: Display P3 и Rec. 2020. Стоит помнить, что математика OKLCH абстрагирована от физических ограничений существующего железа и позволяет накрутить параметры так, что цвет выйдет за рамки возможностей экрана. В этом случае современные браузеры приглушат сверх-насыщенные цвета, но для получения предсказуемого результата все значения следует проверять с помощью интерактивных инструментов.

Какие преимущества, кроме поддержки расширенных цветовых пространств, имеет OKLCH по сравнению с RGB? Допустим, на сайт нужно добавить несколько разноцветных элементов, имеющих одинаковую яркость. Если задавать цвета с помощью HEX-кодов, то для их подбора придется воспользоваться каким-либо графическим редактором или специализированным инструментом. В OKLCH достаточно изменить значение оттенка и оставить неизменными значения яркости и насыщенности:

oklch(0.5 0.16 20)
oklch(0.5 0.16 140)
oklch(0.5 0.16 260)
Автор: 1024x768

Теперь сравним OKLCH с цветовой моделью HSL, в которой цвет тоже задается тремя параметрами. Попробуем подобрать три цвета:

hsl(240, 100%, 50%)
hsl(120, 100%, 50%)
hsl(60, 100%, 50%)
Автор: 1024x768

Видим, что один из получившихся цветов, желтый, заметно светлее, и надпись на прямоугольнике потеряла читаемость. А ведь параметр светлоты был задан одинаковым для всех цветов.

А в чем отличие от модели LCH, у которой были те же самые параметры для работы с цветом и поддержка расширенных цветовых пространств? Попробуем постепенно увеличить яркость синего цвета с помощью обеих моделей:

lch(16.32 59.76 293.61)
lch(26.32 59.76 293.61)
lch(36.32 59.76 293.61)
lch(46.32 59.76 293.61)
lch(56.32 59.76 293.61)

oklch(0.3 0.155 265)
oklch(0.4 0.155 265)
oklch(0.5 0.155 265)
oklch(0.6 0.155 265)
oklch(0.7 0.155 265)
Автор: 1024x768

У LCH наглядно проявился ее главный математический баг, из-за которого у наиболее светлых квадратиков появился фиолетовый оттенок. А у модели OKLCH такого бага нет.

Об OKLCH можно рассказывать еще долго, но я предлагаю перейти к практике.

Подбор цветов

Раньше, если дизайнеру было необходимо подобрать цвет чуть темнее или светлее исходного, приходилось делать это на глаз. С появлением OKLCH эта рутина ушла в прошлое. Уже появились плагины для Figma, умеющие работать с OKLCH, но цвета можно подбирать и с помощью CSS. Допустим, нужно добавить на сайт три разноцветные колонки с кнопками. Цвет каждой кнопки должен быть производным от цвета фона своей секции, но темнее. Цвета кнопок при наведении курсора мыши должны становиться слегка светлее. В приведенном ниже коде добавлены значения оттенков и общее для всех цветов значение насыщенности в переменные CSS, а в стилях элементов прописаны значения для яркости.

HTML:

<div class="section">
  <div class="section__column section__column_color_1">
    <button class="button button_color_1">Кнопка 1</button>
  </div>
  <div class="section__column section__column_color_2">
    <button class="button button_color_2">Кнопка 2</button>
  </div>
  <div class="section__column section__column_color_3">
    <button class="button button_color_3">Кнопка 3</button>
  </div>
</div>

CSS:

:root {
  --color-hue1: 310;
  --color-hue2: 350;
  --color-hue3: 20;
  --color-chroma: 0.11;
}

html {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: border-box;
}

.section {
  display: flex;
}

.section__column {
  flex: 0 0 auto;
  width: 33.33333333%;
  padding: 20px;
}

.section__column_color_1 {
  background-color: oklch(0.8 var(--color-chroma) var(--color-hue1));
}

.section__column_color_2 {
  background-color: oklch(0.8 var(--color-chroma) var(--color-hue2));
}

.section__column_color_3 {
  background-color: oklch(0.8 var(--color-chroma) var(--color-hue3));
}

.button {
  cursor: pointer;
  width: 100%;
  height: 100%;
  background-color: var(--button-color);
  border: none;
  border-radius: 20px;
  text-decoration: none;
  padding: 20px;
  color: oklch(1 0 0);
  font-size: 24px;
  font-weight: bold;
}

.button_color_1 {
  --button-color: oklch(0.35 var(--color-chroma) var(--color-hue1));
}

.button_color_2 {
  --button-color: oklch(0.35 var(--color-chroma) var(--color-hue2));
}

.button_color_3 {
  --button-color: oklch(0.35 var(--color-chroma) var(--color-hue3));
}

.button:hover {
  background-color: oklch(from var(--button-color) 0.45 c h);
}
Автор: 1024x768

Теперь, если будет нужно немного подкорректировать палитру, то после изменения значений переменных сразу изменятся цвета и у колонок и у кнопок. Правда удобно?

Автоматический контраст текста

Поскольку параметр яркости в OKLCH ведет себя предсказуемо, можно автоматически переключать цвет текста кнопки в зависимости от яркости ее фона. Сделать это можно средствами CSS, используя математические функции.

HTML:

<div class="section">
  <div class="section__column">
    <button class="button button_color_1">Белый текст</button>
  </div>
  <div class="section__column">
    <button class="button button_color_2">Черный текст</button>
  </div>
</div>

CSS:

html {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: border-box;
}

.section {
  display: flex;
  padding: 20px;
  gap: 20px;
  background-color: oklch(0.8975 0 0);
}

.section__column {
  flex: 0 0 calc(50% - 10px);
}

.button {
  --button-chroma: 0.12;
  background-color: oklch(var(--button-lightness) var(--button-chroma) var(--button-hue));
  --safe-lightness: clamp(0, var(--button-lightness), 1);
  --text-lightness: calc(1 - round(var(--safe-lightness) - 0.1));
  color: oklch(var(--text-lightness) 0 0);
  cursor: pointer;
  width: 100%;
  height: 100%;
  border: none;
  border-radius: 20px;
  text-decoration: none;
  padding: 20px;
  font-size: 24px;
  font-weight: bold;
}

.button_color_1 {
  --button-hue: 140; 
  --button-lightness: 0.4;
}

.button_color_2 {
  --button-hue: 110; 
  --button-lightness: 0.8;
}
Автор: 1024x768

Видим, что у кнопки с темным фоном текст стал белым, а у другой, со светлым фоном, — черным. Стоит отметить, что в современных браузерах уже появилась поддержка функции contrast-color(), которая автоматически меняет цвет текста в зависимости от яркости фона. Но я решил показать, что эту задачу можно решить и по-другому.

Создание темной темы

Веб-разработчикам, которые используют HEX-коды, при создании темной темы приходится вручную переопределять цвета для элементов интерфейса. С помощью OKLCH эту задачу можно решить математически. В приведенном ниже коде внутри медиазапроса, срабатывающего при включении темной темы в настройках браузера или операционной системы, устанавливается значения для переменной --dark-theme равное единице. Это значение используется как математический множитель: если темная тема включена, то яркость элементов пересчитывается с помощью функции calc().

HTML:

<div class="gallery">
  <div class="gallery-item">
    <img class="gallery-item__image" src="image1.jpg" alt="">
    <div class="gallery-item__text">Камышница</div>
  </div>
  <div class="gallery-item">
    <img class="gallery-item__image" src="image2.jpg" alt="">
    <div class="gallery-item__text">Кряква</div>
  </div>
  <div class="gallery-item">
    <img class="gallery-item__image" src="image3.jpg" alt="">
    <div class="gallery-item__text">Серая цапля</div>
  </div>
</div>

CSS:

:root {
  --dark-theme: 0;
  --background-lightness: calc(0.89 - 0.71 * var(--dark-theme));
  --item-background-lightness: calc(0.95 - 0.71 * var(--dark-theme));
  --item-text-lightness: calc(0.19 + 0.69 * var(--dark-theme));
}

@media (prefers-color-scheme: dark) {
  :root { 
    --dark-theme: 1; 
  }
}

html {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: border-box;
}

.gallery {
  display: flex;
  gap: 10px;
  padding: 20px;
  background-color: oklch(var(--background-lightness) 0 0);
}

.gallery-item {
  flex: 0 0 calc(33.333% - 6.67px);
  padding: 10px;
  background-color: oklch(var(--item-background-lightness) 0 0);
}

.gallery-item__image {
  display: block;
  width: 100%;
}

.gallery-item__text {
  font-size: 24px;
  line-height: 1.0;
  font-weight: bold;
  text-align: center;
  padding-top: 5px;
  color: oklch(var(--item-text-lightness) 0 0);
}
Светлая тема
Светлая тема
Автор: 1024x768
Темная тема
Темная тема
Автор: 1024x768

Стоит ли начать использовать OKLCH?

На мой взгляд, OKLCH — это решение, избавляющее от многих проблем при работе с цветом. Как минимум, с этой цветовой моделью стоит познакомиться.

Автор не входит в состав редакции iXBT.com (подробнее »)

0 комментариев

Добавить комментарий

Сейчас на главной

Новости

Публикации

На глубине 2900 км ИИ нашел шесть неизвестных структур, окружающих ядро Земли

Строение глубинных слоев Земли до сих пор остается одной из самых сложных областей для прямого изучения. В то время как внешняя поверхность планеты картографирована с высокой точностью, ее недра на...

Как защититься дома от комаров: эффективные способы и что делать при укусе

Надежная защита дома от комаров — это не просто закрытые форточки, а продуманный комплекс барьеров и современных средств. С наступлением тепла назойливые насекомые способны испортить не...

Закрылки больше не нужны: самолетом предлагают управлять с помощью плазмы и нейросетей

Подъемная сила самолетного крыла возникает из-за разницы давлений. Когда поток набегающего воздуха встречает переднюю кромку профиля, он разделяется на две части. Нижняя поверхность крыла...

ГАЗ-24-95: полноприводная «Волга» для охоты Брежнева, которую собрали всего в пяти экземплярах

В 1974 году на Горьковском автозаводе собрали пять легковых седанов с дорожным просветом 205 миллиметров и кулачковыми блокировками в обоих мостах. В закрытых заводских документах проект проходил...

Новая передовая модель GPT-6 Astra, а также свежие похождения Роя AI: главное за неделю

Самые интересные новости финансов и технологий в России и мире за неделю: Claude возможно решил математическую супер-задачу, бензиновый кризис в России продолжается, овербукинг легализуют...

Лук и стрелы изобрели 80 000 лет назад на территории современного Узбекистана? Что нашли в гроте Оби-Рахмат

История охотничьего вооружения — это последовательное увеличение дистанции между человеком и его добычей. Чем дальше охотник находится от опасного зверя, тем ниже риск получить травму и...