专业级色彩工具包,提供三种调色板生成算法(Ant Design、推荐算法、OKLCH)、颜色格式转换、WCAG 无障碍对比度检测与暗色模式支持
@skyroc/color 是一个专业级颜色工具包,面向设计系统和主题引擎场景,提供:
底层依赖 colord(基础颜色解析与转换)和 culori(OKLCH 色彩空间与 WCAG 对比度)。
getColorPalette根据输入颜色生成 11 档色板。第二个参数可以直接传算法名,也可以传完整配置对象:
type ColorPaletteConfig =
| PaletteAlgorithm
| {
algorithm?: PaletteAlgorithm; // default: 'antd'
darkTheme?: boolean; // default: false,仅 antd 算法生效
darkThemeMixColor?: string; // default: '#141414',仅 antd 算法生效
};
function getColorPalette(
color: AnyColor,
config?: ColorPaletteConfig // default: 'antd'
): Map<ColorPaletteNumber, string>;| 参数 | 说明 |
|---|---|
color | 任意合法颜色值(hex、rgb、hsl、css 色名等),内部统一归一化为小写 6 位 hex |
config | 算法名 'antd'(默认)/ 'recommended' / 'oklch',或含 darkTheme 等选项的配置对象 |
import { getColorPalette } from '@skyroc/color';
// Ant Design 算法(默认)
const antdMap = getColorPalette('#1677ff');
console.log(antdMap.get(500)); // 主色
// 推荐算法
const recommendMap = getColorPalette('#1677ff', 'recommended');
console.log(recommendMap.get(300)); // 300 档色值
// OKLCH 算法
const oklchMap = getColorPalette('#1677ff', 'oklch');
console.log(oklchMap.get(500)); // 感知均匀的主色
// antd 暗色主题变体
const darkMap = getColorPalette('#1677ff', { algorithm: 'antd', darkTheme: true });getPaletteColorByNumber快捷取指定色阶的 hex 值:
function getPaletteColorByNumber(
color: AnyColor,
number: ColorPaletteNumber,
config?: ColorPaletteConfig // default: 'antd'
): string;import { getPaletteColorByNumber } from '@skyroc/color';
const hex = getPaletteColorByNumber('#1677ff', 200);
const oklchHex = getPaletteColorByNumber('#1677ff', 200, 'oklch');
const darkHex = getPaletteColorByNumber('#1677ff', 200, { darkTheme: true });基于 Ant Design 的 HSV 色彩空间算法。以输入色为第 6 档(主色),向浅色方向(1-5 档)递增亮度、递减饱和度,向深色方向(7-11 档)递减亮度、递增饱和度,同时对色相做小幅偏移。
getAntDPaletteColorByIndex按 ColorIndex(1-11)取单个色阶:
function getAntDPaletteColorByIndex(
color: AnyColor,
index: ColorIndex // 1-11,6 为主色
): string;import { getAntDPaletteColorByIndex } from '@skyroc/color';
const main = getAntDPaletteColorByIndex('#1677ff', 6); // 主色,原色返回
const light = getAntDPaletteColorByIndex('#1677ff', 1); // 最浅
const dark = getAntDPaletteColorByIndex('#1677ff', 11); // 最深getAntDColorPalette生成完整 11 档色板,支持暗色主题变体:
function getAntDColorPalette(
color: AnyColor,
darkTheme?: boolean, // default: false
darkThemeMixColor?: string // default: '#141414'
): string[];暗色模式通过将各档与 darkThemeMixColor 按预设透明度混合生成,适合深色背景场景。
import { getAntDColorPalette } from '@skyroc/color';
// 亮色主题
const lightPalette = getAntDColorPalette('#1677ff');
// => ['#e6f4ff', '#bae0ff', ..., '#001d66', '#00114d']
// 暗色主题
const darkPalette = getAntDColorPalette('#1677ff', true);
// 自定义暗色混合底色
const customDark = getAntDColorPalette('#1677ff', true, '#1a1a2e');通过 CIE76 色差(deltaE)在内置 Tailwind 色板中找到最近色族,然后以输入色与匹配色阶的 HSL 色相差和饱和度比率为基准,对该色族的每一档做色相偏移与饱和度缩放,生成风格一致的 11 档色板。
getRecommendedColorPalette返回完整的 ColorPaletteMatch,包含色族名、所有色阶、主色(500 档)和匹配色:
function getRecommendedColorPalette(color: string): ColorPaletteMatch;import { getRecommendedColorPalette } from '@skyroc/color';
const result = getRecommendedColorPalette('#6366f1');
console.log(result.name); // 色族名
console.log(result.main.hex); // 500 档 hex
console.log(result.match.number); // 输入色最接近的色阶编号
console.log(result.colorMap.get(200)); // 取 200 档getRecommendedPaletteColorByNumber快捷取推荐色板中指定色阶:
function getRecommendedPaletteColorByNumber(color: string, number: ColorPaletteNumber): string;getRecommendedColorPaletteFamily只要色族本身(名字 + 11 档),不要 main / match / colorMap 这些匹配元信息时用它。
统一入口 getColorPalette(color, 'recommended') 内部走的就是这个函数:
function getRecommendedColorPaletteFamily(color: string): ColorPaletteFamily;基于 OKLCH 感知均匀色彩空间的专业调色板生成器,灵感来自 Apple Human Interface Guidelines。相比 HSV/HSL,OKLCH 能保证不同色相在同一明度下的视觉亮度一致。
核心特性:
generateOklchPalette基础 OKLCH 色板生成:
function generateOklchPalette(color: string): ColorPaletteFamily;import { generateOklchPalette } from '@skyroc/color';
const family = generateOklchPalette('#6366f1');
console.log(family.name); // 自动命名
console.log(family.palettes); // 11 档 { hex, number }[]getOklchColorPalette返回 ColorPaletteMatch,自动找到与输入色最接近的色阶:
function getOklchColorPalette(color: string): ColorPaletteMatch;import { getOklchColorPalette } from '@skyroc/color';
const result = getOklchColorPalette('#6366f1');
console.log(result.match.number); // 输入色匹配到的色阶
console.log(result.main.hex); // 500 档getOklchPaletteColorByNumber快捷取指定色阶的 hex:
function getOklchPaletteColorByNumber(color: string, number: ColorPaletteNumber): string;generateOklchPaletteAdvanced支持自定义配置的高级生成:
function generateOklchPaletteAdvanced(color: string, options?: OklchPaletteOptions): ColorPaletteFamily;import { generateOklchPaletteAdvanced } from '@skyroc/color';
// 关闭色相旋转,使用自定义明度曲线
const palette = generateOklchPaletteAdvanced('#6366f1', {
appleHueShift: false,
lightnessCurve: [0.97, 0.94, 0.89, 0.82, 0.74, 0.66, 0.58, 0.5, 0.43, 0.38, 0.26]
});
// 以 600 档为基准反推色度强度
const palette600 = generateOklchPaletteAdvanced('#6366f1', {
forceStep: 600
});
lightnessCurve必须恰好 11 个值(顺序为 50 → 950),长度不符会直接抛错而不是静默回退。
forceStep只改变反推基准色度时参照的档位,不会把输入色原样放进该档——需要精确保留输入色请用generateOklchPaletteAnchored。
generateOklchPaletteAnchored精确保留输入色的增强版本。在匹配档位上使用原始输入色(不做任何近似),其余档位的明度曲线整体平移以穿过该点,并附带每档的 OKLCH 数值与 CSS 字符串:
function generateOklchPaletteAnchored(color: string, forceStep?: ColorPaletteNumber): ColorPaletteFamilyWithOklch;import { generateOklchPaletteAnchored } from '@skyroc/color';
const result = generateOklchPaletteAnchored('#6366f1');
console.log(result.matchedStep); // 500
console.log(result.palettes[5].hex); // '#6366f1'(精确保留)
console.log(result.palettes[5].oklchCss); // 'oklch(55.69% 0.215 277.01)'
console.log(result.inputOklchCss); // 输入色的 OKLCH CSS
// 强制放在 600 档
const result600 = generateOklchPaletteAnchored('#6366f1', 600);
console.log(result600.palettes[6].hex); // '#6366f1'
generateOklchPaletteEx是本函数的旧别名,已标记@deprecated,行为完全一致。
getContrastRatio计算两个颜色之间的 WCAG 对比度(范围 1-21):
function getContrastRatio(color1: string, color2: string): number;import { getContrastRatio } from '@skyroc/color';
const ratio = getContrastRatio('#1677ff', '#ffffff');
console.log(ratio); // e.g. 3.98meetsWcagContrast判断对比度是否满足 WCAG 要求:
function meetsWcagContrast(
ratio: number,
level?: WcagLevel, // default: 'AA'
textSize?: TextSize // default: 'normal'
): boolean;| 等级 | 正常文字 | 大号文字 |
|---|---|---|
| AA | >= 4.5 | >= 3.0 |
| AAA | >= 7.0 | >= 4.5 |
import { getContrastRatio, meetsWcagContrast } from '@skyroc/color';
const ratio = getContrastRatio('#1677ff', '#ffffff');
meetsWcagContrast(ratio, 'AA', 'normal'); // false(4.5 要求)
meetsWcagContrast(ratio, 'AA', 'large'); // true(3.0 要求)generateOklchPaletteWithContrast生成色板并附带完整的 WCAG 对比度分析:
function generateOklchPaletteWithContrast(color: string): PaletteContrastInfo;import { generateOklchPaletteWithContrast } from '@skyroc/color';
const info = generateOklchPaletteWithContrast('#1677ff');
// 查看各档与白色的对比度
info.contrastVsWhite.forEach((ratio, number) => {
console.log(`${number}: ${ratio.toFixed(2)}`);
});
// 白底上满足 AA 的色阶
console.log(info.passAAonWhite); // e.g. [600, 700, 800, 900, 950]
// 每档推荐的文字颜色(黑或白)
console.log(info.recommendedTextColor.get(500)); // '#ffffff' 或 '#000000'findAccessibleTextColor在色板中找到满足 WCAG AA 标准的最佳文字色阶:
function findAccessibleTextColor(
paletteColor: string,
backgroundColor: string,
preferDark?: boolean // default: true
): ColorPaletteNumber | null;import { findAccessibleTextColor } from '@skyroc/color';
// 在白色背景上,用 #1677ff 色板中找深色文字
const step = findAccessibleTextColor('#1677ff', '#ffffff', true);
console.log(step); // e.g. 700
// 在深色背景上找浅色文字
const lightStep = findAccessibleTextColor('#1677ff', '#1a1a2e', false);generateDarkModePalette使用整体压暗的明度曲线生成暗色主题色板。档位号语义与亮色色板一致——50 最亮(L=0.96)、950 最暗(L=0.18):
function generateDarkModePalette(color: string): ColorPaletteFamily;import { generateDarkModePalette } from '@skyroc/color';
const darkPalette = generateDarkModePalette('#1677ff');
// darkPalette.palettes[0].hex → 50 档(最亮)
// darkPalette.palettes[10].hex → 950 档(最暗)暗色主题中需要深色背景时应取 900 / 950 档,而不是依赖档位号被翻转。这样
--primary-50之类的 CSS 变量在明暗两套主题下含义保持一致。
import { isValidColor, getHex, getRgb, getHsl, getHsv, transformHslToHex } from '@skyroc/color';
isValidColor('#1677ff'); // true
isValidColor('not-a-color'); // false
getHex('rgb(22, 119, 255)'); // '#1677ff'
getRgb('#1677ff'); // { r: 22, g: 119, b: 255, a: 1 }
getHsl('#1677ff'); // { h: 215, s: 100, l: 54, a: 1 }
getHsv('#1677ff'); // { h: 215, s: 91, v: 100, a: 1 }
transformHslToHex({ h: 215, s: 100, l: 54 }); // '#1677ff'import { getDeltaE } from '@skyroc/color';
// CIE76 色差(0 = 完全相同,1 = 最大差异)
const delta = getDeltaE('#1677ff', '#1890ff');
console.log(delta); // e.g. 0.035import { addColorAlpha, mixColor, transformColorWithOpacity } from '@skyroc/color';
// 添加透明度
addColorAlpha('#1677ff', 0.5); // '#1677ff80'
// 混合两种颜色
mixColor('#1677ff', '#ff4d4f', 0.5); // 50% 混合
// 将半透明色转为在指定背景上的不透明近似色
// 适合不支持透明度的场景(如某些 PDF 渲染器)
transformColorWithOpacity('#1677ff', 0.3); // 白底近似
transformColorWithOpacity('#1677ff', 0.3, '#000000'); // 黑底近似import { adjustLightness, lightenColor, darkenColor, isWhiteColor } from '@skyroc/color';
// adjustLightness:正数变亮,负数变暗(范围 -100 到 100)
adjustLightness('#1677ff', 20); // 变亮
adjustLightness('#1677ff', -20); // 变暗
// lightenColor / darkenColor(范围 0-100)
lightenColor('#1677ff', 20);
darkenColor('#1677ff', 20);
// 判断是否为白色
isWhiteColor('#ffffff'); // true
isWhiteColor('#fafafa'); // falseimport { getColorName } from '@skyroc/color';
// 在 1500+ 色名表中查找最近匹配
getColorName('#1677ff'); // e.g. 'Dodger Blue'
getColorName('#ff0000'); // 'Red'
getColorName('#2ecc71'); // e.g. 'Shamrock'匹配算法综合 RGB 欧氏距离和 HSL 距离(HSL 权重为 2 倍),先做精确匹配,未命中时取加权距离最小的色名。
colorPalettesTailwind 风格的预设色板数据,包含 22 个色族:
import { colorPalettes } from '@skyroc/color';
// 色族列表
const names = colorPalettes.map(f => f.name);
// ['Slate', 'Gray', 'Zinc', 'Neutral', 'Stone',
// 'Red', 'Orange', 'Amber', 'Yellow', 'Lime',
// 'Green', 'Emerald', 'Teal', 'Cyan', 'Sky',
// 'Blue', 'Indigo', 'Violet', 'Purple', 'Fuchsia',
// 'Pink', 'Rose']
// 每族 11 档 (50, 100, 200, ..., 950)
const bluePalette = colorPalettes.find(f => f.name === 'Blue');
console.log(bluePalette?.palettes);
// [{ hex: '#eff6ff', number: 50 }, ..., { hex: '#172554', number: 950 }]这些预设数据被推荐算法用作 deltaE 匹配的参照基准。
colorNameMaphex → 色名 的查找表,由内置的 1500+ 条色名数据折叠而成,供 getColorName 做精确匹配时使用:
import { colorNameMap } from '@skyroc/color';
colorNameMap['#1677ff']; // 精确命中时返回色名,未收录则为 undefined需要「最近匹配」而不是「精确命中」时用 getColorName——它在表里找不到时会退回加权距离最小的那一条。
| Ant Design | 推荐算法 | OKLCH | |
|---|---|---|---|
| 色彩空间 | HSV | HSL + deltaE | OKLCH(感知均匀) |
| 色阶数量 | 11 档(索引 1-11) | 11 档(50-950) | 11 档(50-950) |
| 主色位置 | 第 6 档 | 500 档 | 500 档(可自定义) |
| 感知均匀性 | 一般 | 依赖预设数据 | 优秀 |
| 色度补偿 | 无 | 无 | 有(按色相族自适应) |
| 色相旋转 | 线性偏移 | 等比映射 | Apple 风格自然旋转 |
| 暗色模式 | 混色法 | 不支持 | 反转明度曲线 |
| WCAG | 不支持 | 不支持 | 完整支持 |
| sRGB 色域映射 | 无 | 无 | 二分法精确映射 |
| OKLCH 值输出 | 不支持 | 不支持 | 支持(generateOklchPaletteAnchored) |
| 适用场景 | 兼容 Ant Design 生态 | 需要 Tailwind 风格一致性 | 设计系统、无障碍要求高的场景 |
选择建议:
从品牌色一键生成完整色板,用于 CSS 变量或设计 Token:
import { generateOklchPaletteAnchored } from '@skyroc/color';
const brand = generateOklchPaletteAnchored('#6366f1');
// 输出为 CSS 变量
brand.palettes.forEach(({ hex, number, oklchCss }) => {
console.log(`--color-primary-${number}: ${hex};`);
console.log(`--color-primary-${number}-oklch: ${oklchCss};`);
});确保界面文字在各色阶背景上可读:
import { generateOklchPaletteWithContrast } from '@skyroc/color';
const info = generateOklchPaletteWithContrast('#1677ff');
// 找出适合做白底文字的色阶
console.log('白底 AA 合规色阶:', info.passAAonWhite);
// 为每档自动选择黑/白文字
info.recommendedTextColor.forEach((textColor, step) => {
console.log(`${step} 档背景 → 文字用 ${textColor}`);
});同一品牌色生成亮色和暗色两套色板:
import { generateOklchPalette, generateDarkModePalette } from '@skyroc/color';
const brandColor = '#1677ff';
const lightPalette = generateOklchPalette(brandColor);
const darkPalette = generateDarkModePalette(brandColor);
// 两套色板档位语义一致:50 最浅 → 950 最深
// 区别在于暗色整条明度曲线被压暗,深色背景取 900 / 950 档在不支持透明度的渲染环境中(如某些邮件客户端、PDF),将半透明色转为视觉等效的不透明色:
import { transformColorWithOpacity } from '@skyroc/color';
// 在白色背景上,30% 透明度的蓝色等效于什么不透明色?
const opaqueOnWhite = transformColorWithOpacity('#1677ff', 0.3);
// 在深色背景上
const opaqueOnDark = transformColorWithOpacity('#1677ff', 0.3, '#1a1a2e');色板色阶编号,主色为 500:
type ColorPaletteNumber = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950;单个色阶:
type ColorPalette = {
hex: string;
number: ColorPaletteNumber;
};一组色阶组成的色族:
type ColorPaletteFamily = {
name: string;
palettes: ColorPalette[];
};调色板匹配结果,包含完整色族、色阶映射、主色和匹配色:
type ColorPaletteMatch = ColorPaletteFamily & {
colorMap: Map<ColorPaletteNumber, ColorPalette>;
main: ColorPalette; // 500 档
match: ColorPalette; // 与输入色最接近的档
};Ant Design 算法使用的 1-11 索引,第 6 档为主色:
type ColorIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;调色板生成算法选择:
type PaletteAlgorithm = 'antd' | 'oklch' | 'recommended';| 值 | 算法 | 说明 |
|---|---|---|
'antd' | Ant Design HSV | 经典 HSV 色彩空间算法,兼容 Ant Design 生态 |
'recommended' | 推荐算法 | 基于内置 Tailwind 色板进行 deltaE 匹配 + HSL 比例调整 |
'oklch' | OKLCH 感知均匀 | 基于 OKLCH 色彩空间,支持色度补偿、色相旋转、sRGB 色域映射 |
OKLCH 高级生成选项:
interface OklchPaletteOptions {
/** 是否启用 Apple 风格色相旋转 @default true */
appleHueShift?: boolean;
/** 是否启用色度补偿 @default true */
chromaCompensation?: boolean;
/** 自定义明度曲线(必须恰好 11 个值,顺序为 50 → 950,长度不符会抛错) */
lightnessCurve?: number[];
/** 反推基准色度时参照的档位(不会把输入色原样放进该档) */
forceStep?: ColorPaletteNumber;
}带 OKLCH 数值与 CSS 字符串的扩展类型:
interface ColorPaletteWithOklch extends ColorPalette {
oklch: { l: number; c: number; h: number };
oklchCss: string; // e.g. "oklch(58.5% 0.204 277.1)"
}
interface ColorPaletteFamilyWithOklch {
name: string;
palettes: ColorPaletteWithOklch[];
matchedStep: ColorPaletteNumber;
inputOklch: { l: number; c: number; h: number };
inputOklchCss: string;
}type WcagLevel = 'AA' | 'AAA';
type TextSize = 'normal' | 'large';
interface PaletteContrastInfo {
palette: ColorPaletteFamily;
contrastVsWhite: Map<ColorPaletteNumber, number>;
contrastVsBlack: Map<ColorPaletteNumber, number>;
passAAonWhite: ColorPaletteNumber[];
passAAonBlack: ColorPaletteNumber[];
recommendedTextColor: Map<ColorPaletteNumber, '#ffffff' | '#000000'>;
}src/
├── types/ 类型定义(ColorPalette、ColorPaletteNumber 等)
├── shared/ 基础工具
│ ├── colord.ts colord 封装(格式转换、混合、明暗调节等)
│ └── name.ts 色名匹配(1500+ 色名表最近距离查找)
├── constant/ 内置数据
│ ├── name.ts 色名表 [hex, name][] + hex → name 映射
│ └── palette.ts Tailwind 风格预设色板(22 个色族 × 11 档)
└── palette/ 三种调色板生成算法
├── index.ts 统一入口(getColorPalette / getPaletteColorByNumber)
├── antd.ts Ant Design HSV 算法(11 档,主色在第 6 档)
├── recommend.ts 推荐算法(deltaE 最近色族 + HSL 比例调整)
└── oklch.ts OKLCH 感知均匀算法(含 WCAG、暗色模式)三种算法的数据流向:
输入颜色 (any CSS color)
│
├──► Ant Design 算法
│ HSV 空间 → 色相偏移 + 饱和度/亮度步进 → 11 档色板
│
├──► 推荐算法
│ deltaE 匹配内置色族 → HSL 色相/饱和度比例映射 → 11 档色板
│
└──► OKLCH 算法
OKLCH 空间 → 色度补偿 + 色相旋转 + sRGB 色域映射 → 11 档色板
+ WCAG 对比度分析
+ 暗色模式变体Last updated on