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 комментариев

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

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

Новости

Публикации

У собак нашли человеческий принцип восприятия речи: почему животные ориентируются на согласные звуки

Звуковая волна человеческой речи не содержит физических пауз между словами. На аудиограмме разговорная фраза выглядит как непрерывный сигнал с меняющейся амплитудой и частотой. Паузы в естественной...

Сравнительный обзор трёх портативных ЦАПов: Kiwi Ears Coda, Kiwi Ears Allegro Bal и Kiwi Ears Allegro Pro

Kiwi Ears Coda, Kiwi Ears Allegro Bal и Kiwi Ears Allegro Pro — три бюджетных портативных ЦАП/усилителя с интегрированными USB-C коннекторами и поддержкой эквалайзера. Параметры Kiwi...

OpenAI экстренно остановила обучение новых моделей: зачем создатели ChatGPT пугают мир потерей контроля над ИИ

В технологической индустрии произошло событие, которое сразу вышло на первые полосы деловых и общественно-политических изданий: компания OpenAI объявила об остановке тренировочного процесса своих...

Был ли у жизни шанс развиваться без кислорода? 12 000 древних окаменелостей доказали, что альтернативы не существовало

В городе Дарвин на севере Австралии расположено государственное кернохранилище. В нем под простым навесом на металлических стеллажах хранятся тысячи узких деревянных и пластиковых ящиков. Внутри...

Почему медведи выходят к людям, даже когда в лесу есть еда

Медведя замечают возле посёлка — и объяснение появляется почти сразу: наверное, в лесу ему нечего есть. Я и сама сначала подумала бы так. Особенно осенью, когда зверю нужно накопить...

Дыра на миллион: чем удивит туриста один из самых крупных золотых карьеров мира

На планете есть куча мест, сотворенных матушкой природой, и от них дух захватывает. Горные хребты, лесные массивы, водопады и прочее. Рукотворных чудес уже поменьше, но австралийский золотой рудник...