Теория цвета и практики гибкого кода

Анна Ширяева

Доклад · UI/UX

Теория цвета
и практики гибкого кода

«Вместе с цветом в нашу жизнь приходят эмоции»

Анна Ширяева Frontend-разработчик

Анна Ширяева

  • В IT с 2011 года
  • Frontend разработчица
  • Организатор MoscowJS
  • Прошедшая художку любительница ярких красок
Gamer Коллекционер хобби

О чём доклад

01
Введение
02
Работа с одним цветом
03
Зависимые цвета и гармонии
04
Контраст
05
Темы
06
Магия
07
Заключение
01

Введение

Когда-то я написала внутренний редактор тем...

Он позволял выбирать любые цвета!

editor-good

Когда заказчики с ним играли, почему-то
получалось не очень...

editor-meh

Потому что редактор позволял выбирать любые цвета!

Было бы круто...
Код = логика работы с цветом

Проблемы:

Этим докладом я хочу...

Построить мостик между мирами
bubbles

Вместе с цветом
в нашу жизнь приходит эмоция

Глоссарий

02

Работа с цветом

Начинается с задач

Пространство = система координат

Пространство должно решать задачу

color-spaces

Одновременная настройка
lightness | chroma | hue

Больше оттенков +
предсказуемое изменение цвета

Исправлены баги
например, работа с синими оттенками

Включаем цвет

Lightness (0% - 100% / 0 - 1)

oklch(20% var(--c) var(--hue));
oklch(35% var(--c) var(--hue));
oklch(50% var(--c) var(--hue));
oklch(75% var(--c) var(--hue));
oklch(90% var(--c) var(--hue));
OKLCH [L] шкала
l:
20%
35%
50%
75%
90%

Lightness (0% - 100% / 0 - 1)

--l: 0.5;
--step: 0.15;


oklch(var(--l) [с] [h])

OKLCH [L] шкала
l:
20%
35%
50%
75%
90%

Lightness (0% - 100% / 0 - 1)


  • В oklch() для любого оттенка один и тот же L одинаково светлый.
[L] шкала
l:
90%
oklch
oklch

Chroma

--c: 0.2;
--step: 0.1;


oklch([l] var(--c) [h])

OKLCH [L C] шкала
c \ l:
20%
35%
50%
75%
90%
0.2

Chroma


  • Базовый диапазон (0 ~ 0.4).
  • Но максимум зависит от hue и может быть ~0.5.
OKLCH [L C] шкала
c \ l:
20%
35%
50%
75%
90%
0.4
0.3
0.2
0.1
0

Hue (0 - 360)

oklch([l] [c] X)
OKLCH [L H] шкала, C = 0.25
l \ h:
0
30
60
90
120
150
180
210
240
270
300
330
360
0.6

Hue (0 - 360)

oklch(1 0.05 X) — что получится?
Шкала «помоги девушке выбрать лак для ногтей»
h:
0
30
60
90
120
150
180
210
240
270
300
330
360
0.90

Бонус факт · Дальтонизм

И чувствительность к отдельным оттенкам.

~ 1 из 12 мужчин (8%)
~ 1 из 200 женщин (0.5%)

Цвет · Названия · Шпаргалка

ярче / сочнее c ↑
спокойнее / бледнее c ↓
светлее l ↑
темнее l ↓
воздушнее / мягче / пастельное l ↑ + c ↓
тяжелее / глубже l ↓ + c ↑
кислотнее / неоновое с ↑↑ + l ~ > 60%
чистые l ~ > 50%, c ~ > 0.2
грязные / мутные l ~ < 50%, c ~ < 0.2

«Я так вижу»

h · оттенок 320
c · насыщенность 0.20
l · светлота 65%
background: oklch(65% 0.20 320);

Цвет · Задачи

Монохромная палитра

Цвет · Шпаргалка

03

Зависимые цвета и гармонии

Включаем гармонию

Все классно, но...

from = новые возможности

--base: #004B95;
oklch(from var(--base) l c h)
oklch(from var(--base) calc(l + 0.2) c h)
oklch(from var(--base) l 0.3 h)
oklch(from var(--base) l c calc(h - 200))
oklch(from var(--base) l c h / 0.5)
Demo
base
oklch
oklch + l
oklch + c
oklch + h
oklch + a

Цветовые гармонии

Монохромная
palette-1
Комплементарная
palette-1
Аналоговая
palette-1
Триада
palette-1
Тетрада
palette-1

Комплементарная

--base: oklch(0.65 0.25 350);

oklch(from var(--base) l c calc(h + 180));
Demo
h + 180

Аналоговая

--base-left: oklch(from var(--base) l c calc(h - 45));
--base: oklch(0.65 0.25 305);
--base-right:oklch(from var(--base) l c calc(h + 45));
Demo
h + 180

Можно создавать такие градиенты

--theme-gradient: linear-gradient(
  90deg,
  var(--base-left),
  var(--base),
  var(--base-right)
);

color-mix()

--bg: #0E1016;
--accent: #C08BFF;

--surface-60: color-mix(in oklab, var(--accent) 60%, var(--bg));
--surface-30: color-mix(in oklab, var(--accent) 30%, var(--bg));
color-mix()

Все оттенки — производные от акцента и фона.

100%
60%
30%

Зависимые цвета · Задачи

Производные от акцента
status: ok

Зависимые цвета · Шпаргалка

04

Контраст

HOLYJS

Бонусом нужен еще тонкий текст

HOLYJS

Бонусом нужен еще тонкий текст

Нюансы WCAG

OKLCH и WCAG
oklch(0.66 0 0) ~3.11:1 AA
oklch(0.56 0 0) ~4.65:1 AA
oklch(0.46 0 0) ~7.12:1 AAA
oklch(0 0 0) ~21:1 AAA

OKLCH и WCAG

Разница по L 45% и выше ~ попадание в АА

// цвет фона
--bg: oklch(L C H)
// цвет элемента в зависимости от темы
--contrast: oklch(from var(--bg) calc(l +/- 0.45) c h)

clamp(min, val, max)

Задаёт значение в диапазоне между min и max.
Вычисляется как: max(MIN, min(VAL, MAX)).

Авто-подбор цвета текста
Светлый фон → тёмный текст
Темный фон clamp(0, (l - 0.6) * -1, 1)
Тёмный фон → белый текст
// при -1 контраст провалится в середине диапазона на сером фоне
// -100 мягкая ступенька, -1000 жесткая ступенька
color: oklch(from var(--bg) clamp(0, (l - 0.6) * -100, 1) 0 h)

contrast-color(val)

contrast-color

Контраст · Задачи

Контраст · Шпаргалка

05

Темы

Тема сводится к...
токенам управления цветом
и их производным

Токены из базовых параметров

      :root {
  --theme-l: 0.65;
  --theme-c: 0.25;
  --theme-h: 305;
  --theme-angle: 45; // угол цветовой гармонии
}

Из которых можно собрать все остальное

// hue для цветовой гармонии
      :root {
  --hue1: var(--theme-h);
  --hue2: calc(var(--theme-h) + var(--theme-angle));
  --hue3: calc(var(--theme-h) - var(--theme-angle));
}

Получаем
тему этих слайдов

Можно собрать на from

      :root {
  --base: #F637C6;

  --accent-soft: oklch(from var(--base) calc(l + 15%) calc(c * 0.6) h);
  --accent-deep: oklch(from var(--base) calc(l - 15%) c h);
}
Вся тема из одного OKLCH + from

Меняем только --base — палитра пересчитывается через oklch(from ...).

Можно собрать на color-mix()

      :root {
  --bg: #0E1016;
  --accent: #C08BFF;

  --bg-60: color-mix(in oklab, var(--accent) 60%, var(--bg));
  --bg-30: color-mix(in oklab, var(--accent) 30%, var(--bg));
}
color-mix()

Все оттенки — производные от акцента и фона.

100%
60%
30%

Тему можно переключать

Тема через атрибут

      <div class="container" data-theme="dark"></div>
    
      .container[data-theme="dark"] {
    // тут перенастраиваете токены
}

Тема через :has()

      <input type="radio" name="accent" value="blue" checked="">
<input type="radio" name="accent" value="green" checked="">
      .container:has([name="accent"][value="blue"]:checked)  { --accent: #4DA6FF; }
.container:has([name="accent"][value="green"]:checked) { --accent: #4DE0A0; }

Тема через light-dark()

      color-scheme: light dark;
--accent: light-dark(#F637C6, #FF6ED6);

Тема через @media (prefers-color-scheme: dark/light)

Подстраивается под системные настройки

      @media (prefers-color-scheme: dark) {
  // набор токенов темной темы
}

Темы · Задачи

Темы · Шпаргалка

Вычисляться:
  • из параметров цвета
  • from
  • color-mix()
  • ...
06

Магия

Теория цвета
и практики гибкого кода

Один токен меняет всё: градиент, булеты, подсветки, кнопку и аватар.

ВЫ
Имя Фамилия Должность
08

Заключение

Шпаргалка
«безграничных возможностей»

Основные инструменты:
  • --css-tokens
  • oklch()
  • calc()
  • from
  • color-mix()
  • clamp()

Цветовые пространства = математика цвета в коде.

На математику можно переложить гармонию,
но стиля вам раздаст дизайнер

@it_wildlife

@it_wildlife
see you
0Х

Температура цвета

Температура цвета

теплые

color-wheel

холодные

Температура синего
(--h - 40) = теплее, (--h + 10) = холоднее
Температура синего
(--h - 40) = теплее, (--h + 10) = холоднее
Температура зеленого
(--h - 20) = теплее, (--h + 20) = холоднее
Температура зеленого
(--h - 20) = теплее, (--h + 20) = холоднее
Температура красного
(--h - 20) = холоднее, (--h + 10) = теплее
Температура красного
(--h - 20) = холоднее, (--h + 10) = теплее

Правила сдвига

Теплые

- h (по часовой) = холодеют
+ h (против часовой) = теплеют

Холодные

- h (по часовой) = теплеют
+ h (против часовой) = холодеют

color-wheel-temp

Правила сдвига

  • Требует точечного подбора
color-wheel-temp