mcpField
C
color-palette

color-palette

github.com/arnavpuri设计与 UI17133 次安装5 周前更新
代码仓库

关于 color-palette

为设计与前端工作提供色彩系统生成指导,从起始色构建 OKLCH 色阶、语义令牌并检查对比度。适合需要将颜色应用于 CSS 或 Tailwind 主题的设计者与开发者。

主要功能

  1. 01按 OKLCH 生成 50–950 色阶
  2. 02定义品牌、语义与中性色令牌
  3. 03检查 WCAG 对比度
  4. 04提供暗色模式映射建议
  5. 05生成 Tailwind 配置与 CSS 变量
  6. 06指导色板视觉校验与设计上下文更新

适用场景

  1. 01从品牌色扩展完整色阶
  2. 02检查文本与背景配色是否达标
  3. 03为 CSS 或 Tailwind 创建颜色令牌
  4. 04为暗色主题映射语义颜色

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/arnavpuri/designskills --skill color-palette

安装后在 Claude Code 中输入/color-palette确认已加载。

附带文件scripts/palette.py

详细介绍

颜色调色板生成

从任意起点生成和谐、易于访问且可用于生产环境的颜色系统。

前置条件

生成颜色前,先检查是否已有设计上下文:

  • 阅读 .agents/design-context.md(参见 design-context 技能)。如果其中包含颜色系统,则将这些十六进制值视为唯一可信来源,并在此基础上扩展,而不是替换。
  • 如果代码库中已有设计系统(CSS 变量、Tailwind 主题、tokens.json),则在此基础上扩展,而不是替换。

命名约定(与 design-system、layout-composition 等共用): 基础色阶为 --brand-50 … --brand-950、--gray-50 … --gray-950、--success-*、--warning-*、--error-*、--info-*;语义令牌为 --bg-*、--text-*、--border-*、--interactive-*,以及品牌别名 --color-primary、--color-secondary、--color-accent。


步骤 1:了解色彩理论基础

使用 OKLCH 生成调色板。其明度通道在感知上均匀,因此固定的 L 步长在每种色相下看起来都是相同的视觉变化(在 HSL 中,hsl(60 100% 50%) 黄色的亮度远高于“相同”亮度的 hsl(240 100% 50%) 蓝色)。仅在旧版工具强制要求时使用 HSL。请注意,高色度的 OKLCH 值可能超出 sRGB 色域;转换为十六进制时,应降低色度(保持 L 和 H 不变)。

色轮关系
和谐关系与基色的角度观感
互补色180°高对比、充满活力
类似色±30°和谐、自然
三角色120°、240°鲜明、均衡
分裂互补色150°、210°有对比但张力较弱
四角色90°、180°、270°丰富,需要谨慎平衡
在 OKLCH 中生成和谐配色
:root {
  /* Base brand color in oklch */
  --brand-hue: 250;         /* hue angle */
  --brand-chroma: 0.15;     /* chroma (not HSL saturation) */
  --brand-l: 0.55;          /* lightness */

  --color-primary:       oklch(var(--brand-l) var(--brand-chroma) var(--brand-hue));
  --color-complement:    oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 180));
  --color-analogous-1:   oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 30));
  --color-analogous-2:   oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) - 30));
  --color-triadic-1:     oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 120));
  --color-triadic-2:     oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 240));
  --color-split-comp-1:  oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 150));
  --color-split-comp-2:  oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 210));
}

步骤 2:生成完整的色阶(50-950)

从单个品牌色生成 11 个明度级别(50、100-900、950)。在 OKLCH 中,改变明度,同时保持色相稳定,并在两端略微降低色度。

明度映射
令牌OKLCH 明度用途
500.97染色背景
1000.93悬停背景
2000.87激活背景
3000.78边框
4000.68占位文本
5000.55基础色/主要操作
6000.48主要操作悬停状态
7000.40主要操作激活状态
8000.32浅色背景上的标题
9000.24浅色背景上的正文
9500.16高对比度文本
CSS 实现
:root {
  --brand-hue: 250;
  --brand-chroma: 0.15;

  --brand-50:  oklch(0.97 calc(var(--brand-chroma) * 0.3) var(--brand-hue));
  --brand-100: oklch(0.93 calc(var(--brand-chroma) * 0.4) var(--brand-hue));
  --brand-200: oklch(0.87 calc(var(--brand-chroma) * 0.5) var(--brand-hue));
  --brand-300: oklch(0.78 calc(var(--brand-chroma) * 0.7) var(--brand-hue));
  --brand-400: oklch(0.68 calc(var(--brand-chroma) * 0.85) var(--brand-hue));
  --brand-500: oklch(0.55 var(--brand-chroma) var(--brand-hue));
  --brand-600: oklch(0.48 var(--brand-chroma) var(--brand-hue));
  --brand-700: oklch(0.40 var(--brand-chroma) var(--brand-hue));
  --brand-800: oklch(0.32 calc(var(--brand-chroma) * 0.9) var(--brand-hue));
  --brand-900: oklch(0.24 calc(var(--brand-chroma) * 0.8) var(--brand-hue));
  --brand-950: oklch(0.16 calc(var(--brand-chroma) * 0.7) var(--brand-hue));
}

步骤 3:定义语义颜色

将用途明确的令牌映射到调色板,或定义独立色相。

推荐的语义色相
角色色相(OKLCH)原因
成功145绿色,普遍代表“继续”
警告85琥珀色/黄色,表示谨慎
错误25红色,表示紧急
信息230蓝色,中性信息
:root {
  /* Semantic: success */
  --success-50:  oklch(0.97 0.04 145);
  --success-400: oklch(0.68 0.15 145);  /* dark-mode foreground */
  --success-500: oklch(0.55 0.16 145);
  --success-700: oklch(0.40 0.14 145);

  /* Semantic: warning */
  --warning-50:  oklch(0.97 0.04 85);
  --warning-400: oklch(0.72 0.15 85);
  --warning-500: oklch(0.60 0.16 85);   /* ~4:1 on white: use dark text ON it, 700 for warning TEXT */
  --warning-700: oklch(0.45 0.14 85);

  /* Semantic: error */
  --error-50:  oklch(0.97 0.04 25);
  --error-400: oklch(0.68 0.16 25);
  --error-500: oklch(0.55 0.18 25);
  --error-700: oklch(0.40 0.16 25);

  /* Semantic: info */
  --info-50:  oklch(0.97 0.04 230);
  --info-400: oklch(0.68 0.12 230);
  --info-500: oklch(0.55 0.14 230);
  --info-700: oklch(0.40 0.12 230);
}

只有当产品需要时(警报、徽章、图表),才为语义色相生成完整的 50-950 色阶;50/400/500/700 已足以覆盖大多数 UI。


步骤 4:生成中性色阶

中性色是基础。添加少许来自品牌色的色相倾向,营造暖感。

:root {
  --neutral-hue: var(--brand-hue);
  --neutral-chroma: 0.01; /* barely tinted */

  --gray-50:  oklch(0.98 var(--neutral-chroma) var(--neutral-hue));
  --gray-100: oklch(0.96 var(--neutral-chroma) var(--neutral-hue));
  --gray-200: oklch(0.90 var(--neutral-chroma) var(--neutral-hue));
  --gray-300: oklch(0.83 var(--neutral-chroma) var(--neutral-hue));
  --gray-400: oklch(0.71 var(--neutral-chroma) var(--neutral-hue));
  --gray-500: oklch(0.55 var(--neutral-chroma) var(--neutral-hue));
  --gray-600: oklch(0.45 var(--neutral-chroma) var(--neutral-hue));
  --gray-700: oklch(0.37 var(--neutral-chroma) var(--neutral-hue));
  --gray-800: oklch(0.27 var(--neutral-chroma) var(--neutral-hue));
  --gray-900: oklch(0.20 var(--neutral-chroma) var(--neutral-hue));
  --gray-950: oklch(0.13 var(--neutral-chroma) var(--neutral-hue));
}

步骤 5:确保符合 WCAG 无障碍标准

对比度要求(WCAG 2.2——当前法律/行业标准)
级别正文大号文本(≥24px,或 ≥18.66px / 14pt 粗体)非文本 UI(图标、边框、焦点环、图表标记)
WCAG AA4.5:13:1与相邻颜色的对比度为 3:1(SC 1.4.11)
WCAG AAA7:14.5:1--

对比度 = (L1 + 0.05) / (L2 + 0.05),其中 L1/L2 是较亮/较暗的相对亮度(在线性化 sRGB 中为 0.2126 R + 0.7152 G + 0.0722 B)。对比度不会向上取整:4.49:1 不合格。APCA(Lc 值)是 WCAG 3 的候选草案,可作为第二意见,尤其适用于深色模式,但绝不能将其报告为合规标准。

实用规则
  • 浅色背景上的正文:使用 900 或 950 色阶(按上述亮度映射,可轻松通过 AA)。
  • 深色背景上的正文:使用 50 或 100 色阶。
  • 主按钮:白色文字配 500+ 色阶通常可以通过(L 0.55 的蓝色 ≈ 4.9:1),但亮度为 L 0.55-0.65 的黄色/琥珀色/青色通常不合格——请改用深色文字。务必测量。
  • 禁用状态:浅色背景上使用 400 色阶。禁用元素虽不受 WCAG 约束,但仍应易于区分。
  • 链接:必须通过颜色之外的方式与周围文本区分——为链接添加下划线,或确保其与周围文本的对比度达到 3:1,并在悬停/聚焦时提供非颜色提示。
使用 OKLCH 亮度快速检查对比度

对于近中性色,相对亮度 ≈ L³,因此在亮度极端值下,4.5:1 需要约 0.42-0.45+ 的亮度差(中间范围则需要更大差值)。仅用它筛选候选颜色,然后再测量。

text L 0.20 | bg L 0.97 | diff 0.77 -> ~16.6:1, passes AAA
text L 0.55 | bg L 0.97 | diff 0.42 -> ~4.5:1, borderline AA -- measure; safe for large text
text L 0.57 | bg L 0.97 | diff 0.40 -> ~4.1:1, FAILS AA for normal text
测量,不要猜测

浏览器可直接渲染 OKLCH,但设计上下文中存储的是 hex 值,对比度必须按 sRGB 计算。使用随附的脚本(<color-palette> 和 <design-context> 是这两个技能的目录):

python <color-palette>/scripts/palette.py --from "#2563eb"                 # scale around a brand color
python <color-palette>/scripts/palette.py 250 0.15 --name brand --css      # hue + chroma -> CSS vars
python <color-palette>/scripts/palette.py 250 0.02 --name gray --json      # neutrals as JSON
python <design-context>/scripts/contrast.py "#ffffff" "#2563eb"             # any real pairing

palette.py 会输出每个色阶的 hex 值,以及与白色/黑色的对比度,并标记为 AA(4.5:1)、large/UI(3:1)或 -。超出色域的色阶会降低色度,而不会改变亮度或色相。contrast.py 在检查不通过时会以 1 退出,并建议最接近的合格色阶。

还要检查你实际使用的每一组文本/背景搭配(文本配 --bg-*、按钮标签配 --interactive-*、深色模式配色),而不仅仅是与纯白/纯黑的对比度。


步骤 6:适配深色模式

不要简单地反转色阶,而应重新映射语义用途。

深色模式策略
[data-theme="dark"] {
  /* Backgrounds: use 900/950 instead of 50/white */
  --bg-primary:   var(--gray-950);
  --bg-secondary: var(--gray-900);
  --bg-tertiary:  var(--gray-800);

  /* Text: use 50/100 instead of 900/950 */
  --text-primary:   var(--gray-50);
  --text-secondary: var(--gray-300);
  --text-tertiary:  var(--gray-400);

  /* Surfaces: slightly lighter than bg */
  --surface:       var(--gray-900);
  --surface-hover: var(--gray-800);

  /* Borders: use 700 instead of 200 */
  --border-default: var(--gray-700);

  /* Brand colors: increase lightness for dark bg */
  --interactive-primary: var(--brand-400); /* lighter than 500 */

  /* Semantic: bump to lighter shades */
  --color-success: var(--success-400);
  --color-warning: var(--warning-400);
  --color-error:   var(--error-400);
}

这些名称必须与步骤 10 中浅色模式第 2 层令牌一致——深色模式只重新映射它们。如需完整的深色主题(高程表面、图像、切换控件),请交由 dark-mode 技能处理。

关键原则
  1. 略微降低对比度——纯白配纯黑会过于刺眼。使用 gray-50 配 gray-950。
  2. 在深色模式下略微降低色度——高饱和度颜色在深色背景上会发光。
  3. 深色模式中的高程使用更亮的表面(与浅色模式的阴影相反)。

步骤 7:按行业选择颜色心理学

行业主色原因
金融海军蓝、深蓝、绿色信任、稳定、增长
医疗蓝色、青绿色、白色平静、洁净、信任
食品红色、橙色、黄色食欲、活力、温暖
科技/SaaS蓝色、紫罗兰色、青色创新、可靠
奢侈品黑色、金色、深紫色优雅、独特
环保/绿色绿色、大地色系自然、可持续发展
教育蓝色、橙色、绿色信任、热情、增长
创意鲜明的三原色、霓虹色活力、表达、乐趣

步骤 8:渐变组合

有效渐变的规则
  1. 柔和渐变的色相旋转角度应控制在 60 度以内。
  2. 鲜艳、充满活力的渐变可使用 90–180 度。
  3. 在 oklch() 中书写色标并不会让渐变以 OKLCH 进行插值。没有插值提示时,浏览器会对现代颜色使用 Oklab,对 hex/rgb/hsl 色标使用 sRGB——这两种方式都会直接穿过色彩空间,在相距较远的色相之间可能经过灰色。添加 in oklch,即可沿色相环进行插值(彩虹渐变可添加 longer hue)。
  4. 或者添加一个中间色标,并稍微提高其色度,以避开“灰色死区”。
/* Subtle brand gradient */
.gradient-subtle {
  background: linear-gradient(
    135deg in oklch,
    oklch(0.55 0.15 250),
    oklch(0.55 0.15 280)
  );
}

/* Vibrant hero gradient */
.gradient-vibrant {
  background: linear-gradient(
    135deg in oklch,
    oklch(0.65 0.20 280),
    oklch(0.60 0.22 330),
    oklch(0.65 0.20 20)
  );
}

/* Mesh gradient (modern trend) */
.gradient-mesh {
  background:
    radial-gradient(at 0% 0%, oklch(0.70 0.15 280) 0%, transparent 50%),
    radial-gradient(at 100% 0%, oklch(0.70 0.15 200) 0%, transparent 50%),
    radial-gradient(at 100% 100%, oklch(0.70 0.15 330) 0%, transparent 50%),
    oklch(0.97 0.01 250);
}

步骤 9:生成 Tailwind 配置

Tailwind v4(以 CSS 为先)——将色阶放入 @theme,即可生成 bg-brand-500、text-brand-900 等类名:

@import "tailwindcss";
@theme {
  --color-brand-50:  oklch(0.97 0.045 250);
  --color-brand-500: oklch(0.55 0.15 250);
  --color-brand-900: oklch(0.24 0.12 250);
  /* ...every step 50-950, plus success/warning/error/info */
}

Tailwind v3(tailwind.config.js):

// tailwind.config.js
const brand = {
  50:  'oklch(0.97 0.045 250)',
  100: 'oklch(0.93 0.06 250)',
  200: 'oklch(0.87 0.075 250)',
  300: 'oklch(0.78 0.105 250)',
  400: 'oklch(0.68 0.1275 250)',
  500: 'oklch(0.55 0.15 250)',
  600: 'oklch(0.48 0.15 250)',
  700: 'oklch(0.40 0.15 250)',
  800: 'oklch(0.32 0.135 250)',
  900: 'oklch(0.24 0.12 250)',
  950: 'oklch(0.16 0.105 250)',
};

module.exports = {
  theme: {
    extend: {
      colors: {
        brand,
        success: { /* ... same pattern, hue 145 */ },
        warning: { /* ... same pattern, hue 85 */ },
        error:   { /* ... same pattern, hue 25 */ },
        info:    { /* ... same pattern, hue 230 */ },
      },
    },
  },
};

步骤 10:CSS 自定义属性架构

将令牌分为三层:

/* Layer 1: Primitive (raw values) */
:root {
  --brand-500: oklch(0.55 0.15 250);
  --error-500: oklch(0.55 0.18 25);
  /* ...full --brand-*, --gray-*, semantic scales from Steps 2-4 */
}

/* Layer 2: Semantic (purpose) -- same names design-system uses */
:root {
  --color-primary:       var(--brand-500);
  --interactive-primary: var(--brand-500);
  --color-error:         var(--error-500);
  --bg-primary:          var(--gray-50);
  --text-primary:        var(--gray-900);
  --border-default:      var(--gray-200);
}

/* Layer 3: Component (scoped) */
.btn-primary {
  background: var(--interactive-primary);
  color: white; /* verified >= 4.5:1 against brand-500 */
}

这种三层方法让主题化和深色模式变得轻而易举——只需重新映射第 2 层。


步骤 11:进行视觉验证并保存到设计上下文

  1. 渲染色板页面:编写一个小型 HTML 文件(临时文件),将每个色阶显示为一行色块,并标注令牌、hex 值以及相对于白色/黑色的对比度;另外添加浅色和深色模式下的示例文本/按钮组合。对其截图(例如 npx playwright screenshot --full-page "file://$PWD/swatches.html" swatches.png;深色模式截图时添加 --color-scheme=dark),并使用 Read 查看图像。检查各步骤的间隔是否均匀,有无浑浊或荧光色,以及中性色是否呈现为中性。
  2. 询问是否要写回 .agents/design-context.md(design-context 技能的文件)。只更新有变化的 Color System 行;切勿重写整个文件。将色阶映射到 design-context 角色,并使用 hex 值:
design-context 角色取值来源
Primary--brand-500(如果 500 与白色文本的对比度未达到 4.5:1,则使用 600)
Primary Light / Primary Dark--brand-400 / --brand-700
Secondary / Accent次要色 / 强调色相的 500 色阶
Neutral 50 / 100 / 200 / 500 / 800 / 900对应的 --gray-* 色阶
Success / Warning / Error--success-500 / --warning-500 / --error-500

向用户展示变更行的前后差异,并在保存前征求确认。


快速参考:从单个 Hex 生成调色板

  1. 读取 .agents/design-context.md;将品牌 hex 转换为 OKLCH。
  2. 提取色相,即为品牌色相。
  3. 使用步骤 2 中的明度映射生成 50–950 色阶。
  4. 使用品牌色相生成带色调的中性色(步骤 4)。
  5. 选择语义色相(步骤 3)。
  6. 使用 palette.py / contrast.py 测量对比度(步骤 5)——继续之前先修复未通过的项。
  7. 构建深色模式映射(步骤 6)。
  8. 导出为 CSS 自定义属性或 Tailwind 配置。
  9. 渲染并检查色板页面;询问是否要将 hex 值保存到 design-context(步骤 11)。

评论

支持 Markdown