css-magic-gradient 1.2.0 — гармонии, палитры, WCAG по всей длине и canvas-экспорт

Когда выходила версия 1.1.0, я написал: «это уже другая история». Оказалось, что история продолжается.
В 1.1.0 появились React-хуки, пресеты и базовые инструменты WCAG. Всё это работало, но оставалось ощущение, что возможности color-value-tools под капотом используются на треть. Там есть тетрадные и сплит-комплементарные гармонии. Есть tints, shades, tones с Oklab-интерполяцией. Есть createColorScale для многоточечных шкал. Библиотека их импортировала, но наружу не давала.
Версия 1.2.0 это исправляет.
Что нового
Расширенные генераторы гармоний
Старые генераторы — createComplementaryGradient, createTriadicGradient, createAnalogousGradient — стали другими внутри. Вместо createMixedLinearGradient с HSL-интерполяцией они теперь используют interpolateColors и createColorScale из color-value-tools, с явным параметром interpolationSpace.
ts
import { createComplementaryGradient } from 'css-magic-gradient';
// Было: HSL-интерполяция, 5 шагов
// Стало: oklch по умолчанию, любое пространство на выбор
createComplementaryGradient('#3498db', { steps: 7, interpolationSpace: 'oklch' });
createComplementaryGradient('#3498db', { steps: 7, interpolationSpace: 'oklab' });
В oklch переходы через комплементарные цвета — это почти всегда ровная насыщенность без провала в серость. В oklab — чуть мягче. Разница видна особенно на переходах вроде синий → оранжевый.
У createTriadicGradient появился параметр smoothness — он управляет тем, сколько точек interpolateColors/createColorScale вставляет между якорями:
ts
// smoothness: 3 — только сами три цвета гармонии
createTriadicGradient('#e74c3c', { smoothness: 3 });
// smoothness: 9 — 9 точек через createColorScale, плавный переход
createTriadicGradient('#e74c3c', { smoothness: 9, interpolationSpace: 'oklch' });
Две новые гармонии
Тетрадная — четыре цвета через 90° на цветовом колесе. Поддерживает линейный, радиальный и конический типы:
ts
import { createTetradicGradient } from 'css-magic-gradient';
createTetradicGradient('#9b59b6'); // линейный по умолчанию
createTetradicGradient('#9b59b6', { type: 'conic', steps: 24 }); // конический
createTetradicGradient('#9b59b6', { type: 'radial', interpolationSpace: 'oklab' });
Сплит-комплементарная — базовый цвет плюс два цвета на 150° и 210°. Визуально это что-то среднее между комплементарным и аналогичным: достаточно контрастно, но не так напряжённо, как полный комплемент.
ts
import { createSplitComplementaryGradient } from 'css-magic-gradient';
createSplitComplementaryGradient('#3498db');
createSplitComplementaryGradient('#3498db', { steps: 7, interpolationSpace: 'oklch' });
Тинты, шейды и тоны
Три новых генератора, которых не хватало для типичных дизайн-задач. Все используют функции из color-value-tools с Oklab-интерполяцией — переходы перцептуально ровные.
ts
import { createTintGradient, createShadeGradient, createToneGradient } from 'css-magic-gradient';
// База → белый (тинты через Oklab)
createTintGradient('#3498db', 7, { direction: 'to right' });
// База → чёрный
createShadeGradient('#e74c3c', 5);
// База → серый, можно указать свой оттенок серого
createToneGradient('#9b59b6', 7, { gray: '#707070' });
Полезно, когда нужна карточка с градиентом в фирменном цвете — берёшь createTintGradient и получаешь переход от насыщенного к почти белому без ручного подбора светлого оттенка.
Новые режимы конического и радиального градиентов
У createConicGradient появились три новых опции.
harmonyType — конический градиент через цвета выбранной гармонии, с интерполяцией по всему кругу:
ts
import { createConicGradient } from 'css-magic-gradient';
// Четыре тетрадных цвета, равномерно вокруг круга
createConicGradient('#e74c3c', { harmonyType: 'triadic', steps: 24 });
createConicGradient('#3498db', { harmonyType: 'tetradic', interpolationSpace: 'oklch' });
colorScale — передаёшь произвольный массив цветов, функция интерполирует их по кругу:
ts
// Красный → зелёный → синий → обратно к красному
createConicGradient('#000', {
colorScale: ['#ff0000', '#00ff00', '#0000ff'],
steps: 36,
interpolationSpace: 'oklch',
});
Для createRadialGradient тоже добавился harmonyType — цвета гармонии становятся стопами радиального градиента:
ts
createRadialGradient('#3498db', {
harmonyType: 'triadic',
interpolationSpace: 'oklch',
shape: 'circle',
});
createRadialGradientLayers — вложенные кольца
Утилита, которой раньше не было. Генерирует набор RadialGradientLayer с убывающими размерами и распределёнными по гармонии цветами. Результат — вложенный многослойный эффект, не требующий ручного подбора размеров.
ts
import { createRadialGradientLayers, createRadialGradient } from 'css-magic-gradient';
const layers = createRadialGradientLayers('#3498db', {
count: 4,
harmonyType: 'triadic',
minSizePercent: 20,
maxSizePercent: 100,
});
// layers — готовый массив RadialGradientLayer[]
const gradient = createRadialGradient('#3498db', { layers });
Каждый слой получает цвет из createColorScale по гармонии, размер рассчитывается равномерно от maxSizePercent до minSizePercent. Можно передать в createRadialGradient как есть, или поправить руками перед этим.
Шесть новых пресетов
Предыдущие девять пресетов покрывали основные «настроения» — закат, океан, аврора. Добавились ещё шесть:
ts
import {
forestGradient, // Светло-зелёный → глубокий зелёный леса
goldenHourGradient, // Золото → розовый → тёплый оранжевый
neonGradient, // Электрический зелёный → малиновый → яркий голубой
nordicGradient, // Ледяной синий → серый → почти белый
pastelGradient, // Лаванда → нежно-розовый → бледная мята
deepSpaceGradient, // Почти-чёрный синий → тёмно-фиолетовый → фиолетовый акцент
} from 'css-magic-gradient';
Всё как раньше — просто строки, готовые к использованию как background.
Переработанная доступность
Старые функции работали по принципу «проверим середину градиента». Это приводило к тому, что у градиента с тёмным началом и светлой серединой можно было получить wcagLevel: 'AAA' — при том, что 40% градиента текст не читается вообще.
Теперь проверяется 11 равномерных точек по всей длине.
gradientContrastRatio возвращает теперь минимальный коэффициент контраста по всему градиенту, не средний:
ts
import { gradientContrastRatio } from 'css-magic-gradient';
// Два цвета — сигнатура прежняя, логика внутри изменилась
gradientContrastRatio('#ffffff', '#1a1a2e', '#e94560');
// Массив стопов — новая форма
gradientContrastRatio('#ffffff', ['#1a1a2e', '#c0357a', '#e94560']);
gradientWcagLevel теперь возвращает объект GradientWcagReport вместо просто строки:
ts
import { gradientWcagLevel } from 'css-magic-gradient';
const report = gradientWcagLevel('#ffffff', '#1a1a2e', '#e94560');
// → {
// level: 'AAA',
// minContrast: 8.4,
// problematicStops: []
// }
// Градиент с провалом в середине:
const report2 = gradientWcagLevel('#ffffff', ['#ffffff', '#aaaaaa', '#3498db']);
// → {
// level: 'fail',
// minContrast: 1.07,
// problematicStops: [0, 0.09, 0.18, 0.27, 0.36]
// }
problematicStops — дробные позиции (0–1) где контраст ниже 4.5. Удобно, если хочешь подсветить проблемную зону в редакторе или подсказать пользователю, где поставить фоновую плашку под текст.
bestGradientTextColor теперь принимает массив и умеет возвращать подробный отчёт:
ts
// Как раньше — два цвета, возвращает '#000000' или '#ffffff'
bestGradientTextColor('#1a1a2e', '#e94560');
// Новый режим — массив стопов
bestGradientTextColor(['#1a1a2e', '#c0357a', '#e94560']);
// Подробный результат
const detail = bestGradientTextColor(['#1a1a2e', '#e94560'], { detailed: true });
// → {
// recommended: '#ffffff',
// black: { contrast: 1.8, wcag: 'fail' },
// white: { contrast: 9.3, wcag: 'AAA' },
// }
У createAccessibleGradient появился adjustmentStrategy — раньше функция умела только двигать яркость. Теперь можно двигать насыщенность или оба параметра сразу:
ts
createAccessibleGradient('#3498db', '#ffffff', {
targetLevel: 'AAA',
adjustmentStrategy: 'both', // 'lightness' | 'saturation' | 'both'
});
Работа с CSS-переменными
Добавились две небольшие утилиты, которые пригодятся при работе с design tokens.
ts
import { extractGradientVariables, resolveGradientVariables } from 'css-magic-gradient';
const gradient = 'linear-gradient(var(--start, #ff0000), var(--end))';
// Извлечь имена всех кастомных свойств
extractGradientVariables(gradient);
// → ['--start', '--end']
// Подставить реальные значения
resolveGradientVariables(gradient, { '--end': '#0000ff' });
// → 'linear-gradient(#ff0000, #0000ff)'
// Если переменная есть в строке с fallback — используется fallback.
// Если нет ни переменной в словаре, ни fallback — var() сохраняется как есть.
Позволяет, например, рендерить градиент с реальными цветами на сервере, даже если в браузере он живёт через CSS-переменные.
Экспорт в canvas
Три функции для тех, кому градиент нужен не только как CSS-строка.
gradientToCanvasGradient создаёт нативный CanvasGradient из параметров:
ts
import { gradientToCanvasGradient } from 'css-magic-gradient';
const gradient = gradientToCanvasGradient(
{
type: 'linear',
stops: [
{ color: '#ff9a3c', offset: 0 },
{ color: '#c0357a', offset: 1 },
],
},
ctx,
);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
Поддерживаются все три типа: 'linear', 'radial', 'conic'. Координаты и радиусы опциональны — по умолчанию подхватывают размер канваса.
gradientToImageData и gradientToDataURL рендерят градиент в ImageData или PNG data URL. Полезно для Open Graph-превью или серверной генерации изображений через npm-пакет canvas:
ts
// Для вставки в <img src> или CSS background
const url = gradientToDataURL(
{ type: 'linear', stops: [{ color: '#ff9a3c', offset: 0 }, { color: '#c0357a', offset: 1 }] },
800, 400,
);
// → 'data:image/png;base64,…'
В браузере используется OffscreenCanvas или document.createElement('canvas'). В Node.js — нужен canvas из npm, или любая другая реализация, которая ставит document в globalThis. Если ничего нет — кидается читаемая ошибка с подсказкой, без загадочного Cannot read properties of undefined.
9 новых хуков для Vue и React
Все новые генераторы получили реактивные хуки — одинаковые имена в Vue (ComputedRef<string>) и React (string через useMemo).
ts
// Vue
import {
useTetradicGradient,
useSplitComplementaryGradient,
useTintGradient,
useShadeGradient,
useToneGradient,
useAccessibleGradient,
useComplementaryGradient,
useTriadicGradient,
useAnalogousGradient,
} from 'css-magic-gradient';
// React — то же самое из css-magic-gradient/react
Пример с useAccessibleGradient — хук сам подбирает контрастный градиент на лету:
tsx
// React
const [bgColor, setBgColor] = useState('#3498db');
const gradient = useAccessibleGradient(bgColor, '#ffffff', { targetLevel: 'AAA' });
// При каждом изменении bgColor — градиент пересчитывается и уже гарантированно проходит AAA
vue
<!-- Vue -->
<script setup>
const color = ref('#3498db');
const gradient = useAccessibleGradient(color, ref('#ffffff'), { targetLevel: 'AA' });
</script>
Все хуки SSR-safe — внутри нет обращений к window или document, только строковые вычисления.
Итог
1.2.0 — это в основном раскрытие того, что уже лежало в color-value-tools и просто ждало своего часа. Тетрадные гармонии, сплит-комплементарные, Oklab-тинты, многоточечная проверка WCAG, canvas-экспорт.
Из следующего в планах: unit-тесты (сейчас их нет, и это видно), документированный playground и поддержка hwb() и oklch() напрямую как базовых цветов.
GitHub: github.com/macrulezru/css-magic-gradient
npm: npmjs.com/package/css-magic-gradient