Color functions

Современные CSS-функции для работы с цветом: color-mix, light-dark, oklch, oklab — дают точный контроль над палитрой, тематизацией и восприятием цвета.

Зачем нужно

Классические hex и rgb имеют ограничения: узкая цветовая гамма (sRGB), неперцептивная равномерность (одинаковое числовое изменение не даёт одинакового визуального изменения). Новые функции решают эти проблемы и упрощают создание тем и палитр.

Где используется

  • Создание палитр из одного базового цвета
  • Тёмная / светлая тема через light-dark
  • Смешивание цветов без препроцессоров
  • Широкая цветовая гамма (P3) для HDR-дисплеев
  • Перцептивно равномерные градиенты (oklch)

Предпосылки

oklch — перцептивное цветовое пространство

oklch(L C H) — Lightness (0-100%), Chroma (насыщенность), Hue (оттенок 0-360):

:root {
  /* oklch(lightness chroma hue) */
  --blue: oklch(60% 0.2 250);
  --red: oklch(60% 0.2 25);
  --green: oklch(60% 0.2 145);
  --purple: oklch(60% 0.2 300);

  /* Все имеют ОДИНАКОВУЮ воспринимаемую яркость!
     В rgb это было бы невозможно */
}

.button-blue { background: var(--blue); }
.button-red { background: var(--red); }
.button-green { background: var(--green); }
.button-purple { background: var(--purple); }

Генерация палитры через lightness

:root {
  --hue: 250; /* Базовый оттенок */
  --chroma: 0.15;

  --color-50:  oklch(97% var(--chroma) var(--hue));
  --color-100: oklch(93% var(--chroma) var(--hue));
  --color-200: oklch(85% var(--chroma) var(--hue));
  --color-300: oklch(75% var(--chroma) var(--hue));
  --color-400: oklch(65% var(--chroma) var(--hue));
  --color-500: oklch(55% var(--chroma) var(--hue));
  --color-600: oklch(45% var(--chroma) var(--hue));
  --color-700: oklch(35% var(--chroma) var(--hue));
  --color-800: oklch(25% var(--chroma) var(--hue));
  --color-900: oklch(15% var(--chroma) var(--hue));
}

oklch с прозрачностью

.overlay {
  background: oklch(20% 0 0 / 0.5); /* 50% прозрачный тёмный */
}

oklab — перцептивное смешивание

oklab(L a b) — похож на oklch, но использует координаты a (зелёный-красный) и b (синий-жёлтый):

.element {
  color: oklab(60% -0.1 0.1);
  /* L: яркость, a: зелёный(-) / красный(+), b: синий(-) / жёлтый(+) */
}

oklch удобнее для людей (hue = угол на цветовом колесе). oklab лучше для вычислений и плавных переходов.

color-mix — смешивание цветов

.element {
  /* Смешать 50% красного и 50% синего */
  background: color-mix(in oklch, red, blue);

  /* 70% первого + 30% второго */
  background: color-mix(in oklch, #007bff 70%, white);

  /* Осветление — смешать с белым */
  --light: color-mix(in oklch, var(--color-primary) 80%, white);

  /* Затемнение — смешать с чёрным */
  --dark: color-mix(in oklch, var(--color-primary) 80%, black);
}

Палитра через color-mix

:root {
  --brand: #007bff;

  --brand-50:  color-mix(in oklch, var(--brand) 5%, white);
  --brand-100: color-mix(in oklch, var(--brand) 15%, white);
  --brand-200: color-mix(in oklch, var(--brand) 30%, white);
  --brand-300: color-mix(in oklch, var(--brand) 50%, white);
  --brand-400: color-mix(in oklch, var(--brand) 70%, white);
  --brand-500: var(--brand);
  --brand-600: color-mix(in oklch, var(--brand) 85%, black);
  --brand-700: color-mix(in oklch, var(--brand) 70%, black);
  --brand-800: color-mix(in oklch, var(--brand) 50%, black);
  --brand-900: color-mix(in oklch, var(--brand) 30%, black);
}

Цветовые пространства для смешивания

/* in srgb — классическое смешивание */
color-mix(in srgb, red, blue); /* Тусклый фиолетовый */

/* in oklch — перцептивно равномерное */
color-mix(in oklch, red, blue); /* Яркий фиолетовый */

/* in oklch longer hue — через длинную дугу цветового колеса */
color-mix(in oklch longer hue, red, blue); /* Через зелёный/жёлтый */

light-dark — автоматическая тема

:root {
  color-scheme: light dark; /* Поддержка обеих тем */
}

body {
  background: light-dark(#ffffff, #1a1a1a);
  color: light-dark(#333333, #e0e0e0);
}

.card {
  background: light-dark(#f8f9fa, #2d2d2d);
  border: 1px solid light-dark(#dee2e6, #404040);
  box-shadow: light-dark(
    0 2px 8px rgba(0, 0, 0, 0.08),
    0 2px 8px rgba(0, 0, 0, 0.3)
  );
}

.button {
  background: light-dark(#007bff, #4dabff);
  color: light-dark(white, #1a1a1a);
}

/* Переключение через класс или @media */
:root {
  color-scheme: light; /* По умолчанию светлая */
}

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

/* Или ручное переключение */
.theme-dark {
  color-scheme: dark;
}

color — расширенная цветовая гамма

.vibrant {
  /* Display P3 — шире sRGB, для современных дисплеев */
  background: color(display-p3 1 0.2 0.1);

  /* Fallback для старых браузеров */
  background: #ff3311;
  background: color(display-p3 1 0.2 0.1);
}

/* Проверка поддержки */
@supports (color: color(display-p3 0 0 0)) {
  .vibrant {
    background: color(display-p3 1 0.2 0.1);
  }
}

Относительные цвета (Relative Color Syntax)

:root {
  --brand: oklch(55% 0.2 250);
}

.button {
  background: var(--brand);
}

.button:hover {
  /* Взять --brand и изменить lightness на +10% */
  background: oklch(from var(--brand) calc(l + 0.1) c h);
}

.button:active {
  /* Затемнить */
  background: oklch(from var(--brand) calc(l - 0.1) c h);
}

/* Создать полупрозрачную версию */
.badge {
  background: oklch(from var(--brand) l c h / 0.2);
  color: var(--brand);
}

Частые ошибки

  1. oklch chroma вне диапазона — браузер обрезает до ближайшего допустимого:
    /* Слишком насыщенный — будет обрезан */
    color: oklch(50% 0.5 150); /* 0.5 слишком много для зелёного */
    
  2. light-dark без color-scheme — функция требует color-scheme на элементе или предке
  3. color-mix(in srgb) даёт тусклые промежуточные — используйте in oklch для лучшего результата
  4. Забыли fallback — Display P3 не поддерживается в старых браузерах

Практика

  • Создать палитру из 10 оттенков через oklch (меняя lightness)
  • Использовать color-mix для hover-состояний (осветление/затемнение)
  • Реализовать тёмную тему через light-dark
  • Сравнить градиент в srgb и oklch — увидеть разницу
  • Попробовать relative color syntax для hover-эффектов

Связанные темы

Ресурсы