Все статьи | Разработка

Расчёт цвета: динамическое цветовое оформление на чистом CSS

Расчёт цвета: динамическое цветовое оформление на чистом CSS главное изображение

Вы знаете, что можно динамически менять цветовое оформление страницы без JavaScript или CSS-препроцессоров? Это возможно благодаря магии кастомных свойств CSS, цветовой модели HSL и функции calc(). Они работают с любым фреймворком и веб-технологией без лишних телодвижений. Да здравствует CSS!

В демо на CodePen можно выбрать основной и дополнительный цвета и создать завершённую систему. Это реализовано на ванильном CSS. JavaScript здесь используется только для динамического изменения цветов.

Что нам дают CSS-препроцессоры

Когда заходит речь о системах цветов, на ум приходят несколько полезных функций Sass. Вот наиболее распространённые:

  • lighten, darken();
  • complement();
  • hue();
  • mix();
  • contrast-color().

Некоторые из этих трансформаций можно воссоздать с помощью CSS-фильтров. Например, lighten и darken — это всего лишь значение lightness из HSL. Трансформация hue — это H из HSL. Дополнительные цвета можно рассчитывать с помощью инверсии hue, для этого достаточно прибавить к или отнять 180 от соответствующего значения. Это переносит значение hue на противоположную сторону цветового круга. Функция calc() и кастомные свойства позволяют трансформировать цвета с помощью одного значения.

Ниже рассказывается, как с помощью кастомных свойств CSS и функции calc() воссоздавать lighten() darken(), comlement() и даже триадические сочетания. Также вы узнаете лайфхак, который позволяет делать крутые штуки с color-contrast(). Эти возможности реализованы во всех современных браузерах. Но для Internet Explorer 11 и ниже придётся использовать препроцессор.

Настраиваем окружение

В первую очередь нужно разложить цвета на значения hue, saturation и lightness (тон, насыщенность и светлота) цветовой модели HSL. Можно также использовать значение альфа — прозрачность. Например, переменная для цвета red выглядит так:

--colorPrimary: hsl(0, 100%, 50%);

Объявляем пользовательские свойства со значениями HSL.

--colorPrimary-h: 0;
--colorPrimary-s: 100%;
--colorPrimary-l: 50%;
--colorPrimary: var(--colorPrimary-h), var(--colorPrimary-s), --colorPrimary-l);

Корректируем значения с помощью HSL

Теперь значения из примера выше можно использовать для корректирования цветов. Начать стоит с воссоздания функций lighten и darken.

Определим, на сколько светлее или темнее должен стать цвет. Эти значения сохраним в дополнительных кастомных свойствах.

--lighten-percentage: 20%;
--darken-precentage: 15%;

После определения трансформаций можно записать новые значения. Показатель lightness можно вычислить так.

calc(var(--colorPrimary-l) + var(--lighten-percentage))

Всё вместе выглядит так.

--colorPrimary--light: var(--colorPrimary-h), var(--colorPrimary-s), 
calc(var(--colorPrimary-l) + var(--lighten-percentage)));

Код может показаться сложным. Но здесь только используются базовые значения hue и saturation и уточняется значение lightness.

Читайте также: 7 необычных приёмов и инструментов HTML и CSS

Чтобы реализовать функцию darken, можно вычесть значение lightness или прибавить его, если вам нужны отрицательные значения.

--colorPrimary--dark: var(--colorPrimary-h), var(--colorPrimary-s), 
calc(var(--colorPrimary-l) - var(--darken-percentage)));

Получаем комплементарные цвета и триадические сочетания

цветовой круг

Цветовой круг HSL


Чтобы получать комплиментарные или триадические оттенки, нужно уточнять значение hue базового цвета. Можно создать отдельные переменные или использовать шорткаты и помнить, что цветовой круг HSL изменяется по часовой стрелке от нуля до 360 градусов (см. иллюстрацию выше). То есть чтобы получить комплементарный оттенок, необходимо отнять или прибавить к значению 180 градусов.

комплементарный цвет

Получаем комплементарный оттенок


--colorPrimary--complement: calc(var(--colorPrimary-h) + 180), var(--colorPrimary-s), var(--colorPrimary-l));

Чтобы получить триадическое сочетание, нужно разделить цветовой круг на три части. То есть оттенки можно получить, добавив к базовому значению 120 и 240 соответственно.

Триадические цвета

Триадические сочетания


--colorPrimary--triad1: calc(var(--colorPrimary-h) + 120), var(--colorPrimary-s), var(--colorPrimary-l));
--colorPrimary--triad2: calc(var(--colorPrimary-h) + 240), var(--colorPrimary-s), var(--colorPrimary-l));

Воспроизводим mix()

Режим смешивания mix() более сложный по сравнению с lighten() и darken(). Но его можно воспроизвести с помощью HSL-вычислений.

Чтобы смешать цвета, надо определить их.

--color-1-h: 0;
--color-1-s: 100%;
--color-1-l: 50%;

--color-2-h: 50;
--color-2-s: 80%;
--color-2-l: 50%;

Затем надо получить средние значения.

--avg-1-2-h: calc((var(--color-1-h) + var(--color-2-h)) / 2);
--avg-1-2-s: calc((var(--color-1-s) + var(--color-2-s)) / 2);
--avg-1-2-l: calc((var(--color-1-l) + var(--color-2-l)) / 2);

Теперь можно получить смешанный цвет.

--mixed-color: hsl(var(--avg-1-2-h), var(--avg-1-2-s), var(--avg-1-2-l));

Создаём функцию color-contrast()

Ещё одна ключевая возможность CSS-препроцессоров — использование логических значений. Они позволяют вычислять доступные цвета с помощью функции color-contrast().

Эта функция принимает серию значений: базовый цвет, который выступает в качестве контрастного, значения light и dark. Функция возвращает самый контрастный цвет по отношению к базовому. Это невозможно воспроизвести на чистом CSS, поэтому понадобятся дополнительные хаки.

демонстрация системы цветов

Наглядная демонстрация возможностей системы цветов


Сначала определяем порог контрастности.

--contrastThreshold: 60%;

Затем проверяем, не превышает ли значение lightness порог контрастности. Для этого используем демонстрационную версию системы цветов. Если порог выше яркости основного цвета, возвращается значение light, так как мы умножаем значение lightness на - 100. Например, значение lightness составляет 40, а contrastThreshhold 60. Разница равна - 20. Умножаем это значение на - 100 и получаем 2000. Это белый цвет, так как при значении lightness 100 и выше всегда получается белый.

Когда значение lightness выше contrastThreshhold, получаем обратную ситуацию. Если lightness 90, а contrastThreshold 60, разница составляет 30. Умножаем это значение на - 100 и получаем -3000. Это чёрный цвет, так как lightness ниже нуля.

Возвращаем lightness как L в HSL. Это выглядит так.

.primary {
  background: var(--colorPrimary);

  --switch: calc((var(--colorPrimary-l) - var(--contrastThreshold)) * -100);
  color: hsl(0, 0%, var(--switch));
}

Поскольку HSL — это то, как компьютер, а не пользователь понимает lightness, этот инструмент не идеальный. То есть у кастомных свойств и функции calc() есть недостатки, как у любого другого инструмента.

Заключение

В статье рассмотрели удобные способы работы с кастомными свойствами и функцией calc(). Если у вас есть вопросы или дополнения, пишите их в комментариях.

Адаптированный перевод статьи Calculating Color: Dynamic Color Theming with Pure CSS by Una Kravets.

Аватар пользователя Дмитрий Дементий
Дмитрий Дементий 17 декабря 2019
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
8 декабря 8 месяцев
Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
8 декабря 8 месяцев
Иконка программы PHP-разработчик
Профессия
Разработка веб-приложений на Laravel
8 декабря 8 месяцев
Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
8 декабря 8 месяцев
Иконка программы Верстальщик
Профессия
Вёрстка с использованием последних стандартов CSS
в любое время 5 месяцев
Иконка программы Java-разработчик
Профессия
Разработка приложений на языке Java
8 декабря 10 месяцев
Иконка программы Разработчик на Ruby on Rails
Профессия
Новый
Создает веб-приложения со скоростью света
8 декабря 5 месяцев