Как смешивать цвета и создавать палитры на Sass

Смешивание цветов Sass помогает получить варианты фирменного цвета без ручного подбора. Вы зададите два базовых цвета, соберете палитру и выведете ее в CSS-переменные.

Разберем color.scale(), color.adjust(), color.mix() и CSS-функции. В конце вы проверите контраст текста и фона.

Переменные бренда в Sass

Назовите базовые цвета до расчета светлых и темных вариантов. Такое имя понятнее повторяющегося HEX-кода.

Пример использует красный $toolbox и синий $ol-blue. Запишите их в файле palette.scss через HSL:

@use "sass:color";

$toolbox: hsl(0, 50%, 40%); // #993333
$ol-blue: hsl(210, 50%, 60%); // #6699cc

button {
  background-color: $toolbox;
  background-image: linear-gradient(
    hsl(0, 33%, 52%),
    $toolbox,
    hsl(0, 41%, 39%)
  );
}

Это SCSS. Браузер не понимает переменные с символом $. Dart Sass превращает их в обычный CSS.

Скомпилируйте файл командой sass palette.scss palette.css. Рядом появится файл palette.css. Подключите его к странице:

<link rel="stylesheet" href="palette.css">
<button type="button">Добавить в корзину</button>

Кнопка получит красный фон с градиентом.

Подключайте функции цвета через модуль sass:color.

Глобальные lighten(), darken(), scale-color(), adjust-hue() и mix() объявлены устаревшими в Dart Sass. Используйте color.adjust(), color.scale() и color.mix().

Стога сена в разных оттенках света показывают влияние тональности на палитру

Оттенок света меняет восприятие одной и той же палитры.

Почему lighten и darken дают резкий результат

Старые функции меняют светлоту на фиксированное число процентных пунктов. Значение «осветлить на 50%» легко понять неправильно.

У $toolbox светлота равна 40%. У $ol-blue она равна 60%. Прибавление 50 процентных пунктов даст красному цвету 90%.

Синий цвет упрется в предел 100% и станет белым. При затемнении действует тот же принцип.

.fixed-step {
  color: color.adjust($toolbox, $lightness: 50%);
  background-color: color.adjust($ol-blue, $lightness: 50%);
}
Сравнение базовых цветов и вариантов после фиксированного увеличения светлоты
Сравнение светлоты красного и синего цветов в палитре
Варианты базовых цветов после фиксированного уменьшения светлоты

Светлота HSL задает координату цвета, но не измеряет воспринимаемую яркость.

Два цвета с одинаковой светлотой могут выглядеть по-разному. Поэтому HSL не гарантирует читаемость текста.

Получите оттенки через color.scale

color.scale() меняет канал на долю расстояния до его предела.

Положительное значение светлоты приближает цвет к белому. Отрицательное значение приближает цвет к черному. Исходная светлота влияет на результат.

.scaled {
  color: color.scale($toolbox, $lightness: 50%);
  background-color: color.scale($ol-blue, $lightness: -30%);
}

Красный изменит светлоту с 40% до 70%. Синий при уменьшении на 30% получит 42%.

Пропорциональное осветление сохраняет различия между базовыми цветами
Пропорциональное затемнение создает темные варианты двух базовых цветов
Светлые варианты цветов после масштабирования светлоты
Темные варианты цветов после отрицательного масштабирования светлоты

Значение 100% дает белый цвет. Значение −100% дает черный цвет.

@mixin brand-button($base) {
  background-color: $base;
  background-image: linear-gradient(
    color.scale($base, $lightness: 50%),
    $base,
    color.scale($base, $lightness: -30%)
  );

  &:hover,
  &:focus {
    background-color: color.scale($base, $lightness: 10%);
    background-image: linear-gradient(
      color.scale($base, $lightness: 60%),
      color.scale($base, $lightness: 10%),
      color.scale($base, $lightness: -20%)
    );
  }
}

button {
  @include brand-button($toolbox);
}

button.secondary {
  @include brand-button($ol-blue);
}

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

Для сдвига оттенка используйте color.adjust($ol-blue, $hue: 20deg). Функция color.scale() оттенок не сдвигает.

Сравните функции цвета Sass и CSS

Функции меняют цвет по-разному. Выбирайте их по нужному результату.

ФункцияЧто делаетПримерКогда считает цвет
color.adjust()Прибавляет фиксированное значение каналаcolor.adjust(hsl(210, 50%, 60%), $lightness: 20%)При сборке Sass
color.scale()Проходит долю расстояния до предела каналаcolor.scale(hsl(210, 50%, 60%), $lightness: 50%)При сборке Sass
color.mix()Смешивает два цвета в выбранном пространствеcolor.mix(white, #993333, $weight: 50%, $method: rgb)При сборке Sass
color-mix()Смешивает цвета в браузереcolor-mix(in srgb, white 50%, #993333)Во время работы страницы

Смешайте цвет с собственными тонами

color.mix() рассчитывает промежуточный цвет между двумя исходными. Параметр $weight задает долю первого цвета.

$blue-light: color.mix(white, $ol-blue, $weight: 60%, $method: rgb);
$blue-dark: color.mix(black, $ol-blue, $weight: 30%, $method: rgb);

Параметр $method поддерживается Dart Sass начиная с версии 1.79.0. Значение rgb задает интерполяцию в RGB.

Смешивание в RGB интерполирует цветовые каналы, не повторяя изменение светлоты HSL.

Поэтому результаты color.mix() и color.scale() различаются. Другие пространства интерполяции описаны в документации color.mix().

$light: #fff2b3;
$shadow: #34204f;

$toolbox-light: color.mix($light, $toolbox, $weight: 60%, $method: rgb);
$toolbox-dark: color.mix($shadow, $toolbox, $weight: 30%, $method: rgb);
$blue-light: color.mix($light, $ol-blue, $weight: 60%, $method: rgb);
$blue-dark: color.mix($shadow, $ol-blue, $weight: 30%, $method: rgb);

.card {
  background-color: $blue-light;
  border-color: $blue-dark;
}
Схема смешивания базового цвета с цветом света и тени
Теплый светлый тон в палитре двух базовых цветов
Темный оттенок палитры после смешивания с цветом тени
Варианты палитры с общими цветами света и тени
Палитра с красноватым светлым и темным тоном
Палитра с прохладными оттенками воды и зелени
Контрастные светлые и темные варианты одной цветовой схемы
Смешивание цветов бренда с дополнительным светлым тоном
Смешивание цветов бренда с дополнительным темным тоном
Несколько настроений палитры на основе двух базовых цветов

Замените $light и $shadow, чтобы изменить настроение всей палитры. Sass пересчитает зависимые смеси при следующей сборке.

Соберите палитру и выведите CSS-переменные

Карта Sass хранит базовые цвета. Цикл @each создает свойства в :root.

@use "sass:color";

$brands: (
  "toolbox": #993333,
  "ol-blue": #6699cc
);

$light: white;
$shadow: black;

:root {
  @each $name, $base in $brands {
    --color-#{$name}: #{$base};
    --color-#{$name}-light: #{color.mix($light, $base, $weight: 50%, $method: rgb)};
    --color-#{$name}-dark: #{color.mix($shadow, $base, $weight: 50%, $method: rgb)};
  }
}

.button {
  background-color: var(--color-toolbox);
  color: white;
}

.button:hover {
  background-color: var(--color-toolbox-dark);
}

Интерполяция #{…} вставляет значение Sass в пользовательское свойство CSS.

Запустите sass palette.scss palette.css. Компилятор создаст 6 CSS-переменных. Итоговый CSS будет выглядеть так:

:root {
  --color-toolbox: #993333;
  --color-toolbox-light: #cc9999;
  --color-toolbox-dark: #4d1a1a;
  --color-ol-blue: #6699cc;
  --color-ol-blue-light: #b3cce6;
  --color-ol-blue-dark: #334d66;
}

.button {
  background-color: var(--color-toolbox);
  color: white;
}

.button:hover {
  background-color: var(--color-toolbox-dark);
}

Добавьте на страницу кнопку с классом button. При наведении фон изменится на темный вариант.

Меняйте значение цвета, например #993333, в карте $brands. Затем повторите компиляцию.

Имена ключей toolbox и ol-blue оставляйте прежними. Они определяют имена CSS-переменных, которые используют стили кнопки.

Когда выбрать color-mix и относительные цвета в CSS

Sass считает цвета во время сборки, поэтому браузер получает готовые значения.

Изменение CSS-переменной без пересборки не обновит оттенки Sass. Для темы, которая меняется во время работы страницы, используйте CSS-функции.

Нативная функция color-mix() смешивает цвета в браузере. Она принимает CSS-переменную:

:root {
  --brand: #6699cc;
}

.badge {
  background-color: #b3cce6;
}

@supports (background-color: color-mix(in srgb, white, black)) {
  .badge {
    background-color: color-mix(in srgb, white 50%, var(--brand));
  }
}

При изменении --brand браузер пересчитает фон без запуска Sass.

Условие @supports проверяет поддержку объявления. Запасной цвет останется для браузера без этой функции.

Относительный синтаксис цвета меняет каналы исходного цвета:

.badge-relative {
  background-color: #b3cce6;
}

@supports (background-color: hsl(from red h s l)) {
  .badge-relative {
    background-color: hsl(
      from var(--brand)
      h s calc(l + (100 - l) * 0.5)
    );
  }
}

В относительном HSL канал l принимает значение от 0 до 100. Формула увеличивает светлоту на половину оставшегося расстояния.

Выбирайте Sass для дизайн-токенов и статичной палитры. Выбирайте CSS-функции для темы, которая меняется через переменные.

Проверьте контраст текста и фона

Гармоничная палитра не гарантирует читаемость.

Проверяйте обычное состояние, наведение, фокус и выбранное состояние.

Критерий 1.4.3 WCAG 2.1 задает пороги для уровня AA. Обычному тексту нужен контраст 4,5:1.

Для крупного текста нужен контраст 3:1. Уровень AAA требует 7:1 для обычного текста и 4,5:1 для крупного.

Критерий нетекстового контраста задает порог 3:1 для значимых границ и состояний элементов.

Для непрозрачных цветов рассчитайте контраст в консоли браузера. Функция принимает шестизначные HEX-коды:

function contrast(hex1, hex2) {
  function luminance(hex) {
    const channels = hex.replace(/^#/, "").match(/.{2}/g).map(part => {
      const value = parseInt(part, 16) / 255;
      return value <= 0.04045
        ? value / 12.92
        : ((value + 0.055) / 1.055) ** 2.4;
    });
    return channels[0] * 0.2126
      + channels[1] * 0.7152
      + channels[2] * 0.0722;
  }

  const a = luminance(hex1);
  const b = luminance(hex2);
  return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
}

console.log(contrast("#ffffff", "#993333"));

Для пары #000000 и #ffffff функция вернет 21.

Если коэффициент ниже порога, измените цвет текста или фона. На градиенте проверьте участок под буквами с самым слабым результатом.

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

Как выбрать функцию цвета для палитры

  • color.adjust() – используйте фиксированное изменение канала или сдвиг оттенка.
  • color.scale() – получайте светлые и темные варианты с учетом исходной светлоты.
  • color.mix() – добавляйте общий цвет света или тени к нескольким базовым цветам.
  • Карта Sass и @each – экспортируйте дизайн-токены как свойства --color-*.
  • color-mix() и относительные цвета CSS – меняйте тему без пересборки Sass.

Совет от нашей редакции: сначала проверьте одну кнопку с текстом. Сравните обычное состояние, наведение и клавиатурный фокус. После этого применяйте палитру ко всему интерфейсу.

Комментарии

Оставьте свой комментарий
Пока никто не оставил комментариев