内容
# 可访问色板
[](https://www.npmjs.com/package/accessible-color-palette)
一个TypeScript库,从任何十六进制颜色生成**WCAG 2.2 AA合规的单色调色板**。调色板算法没有外部依赖——WCAG数学直接实现。
给定一个十六进制颜色和一个背景主题(`'white'` | `'black'`),它生成6种色调——**100, 300, 600, 700, 800, 900**——其中每种色调都满足与主题的对比度要求。同时返回一个使用地图,描述哪些色调对满足AA标准的普通文本(4.5:1)和哪些对满足AA标准的大文本/UI组件(3:1)。
作为ESM库、CLI和MCP服务器与AI助手一起使用。
## 安装
```bash
npm install accessible-color-palette
```
## 用法
### 作为CLI
```bash
npx accessible-color-palette <hex> <theme> [options]
```
| 参数/选项 | 描述 |
| --- | --- |
| `hex` | 十六进制颜色——带或不带`#`,3或6个字符 |
| `theme` | 背景主题:`white` \| `black` |
| `--prefix <name>` | CSS变量前缀(默认值:`color`) |
| `--json` | 输出完整的调色板+使用地图作为JSON |
| `-h, --help` | 显示帮助 |
```bash
# 默认情况下,生成CSS令牌和WCAG清单(默认)
npx accessible-color-palette 1F7A54 white
# 自定义前缀
npx accessible-color-palette 1F7A54 white --prefix brand
# 原始JSON
npx accessible-color-palette 1F7A54 white --json
```
输出(默认):
```css
/*
* WCAG AA配对清单——来源:#1f7a54 · 主题:white
*
* 正文文本(任意字体大小,≥4.5:1):
* shade-700 (#207c55) → white, 100
* shade-800 (#124630) → white, 100, 300
* ...
*/
:root {
--color-100: #e3f8ef; /* ✅ text→900·800·700 ⚠️ lg→600 */
--color-700: #207c55; /* ✅ text→white·100 ⚠️ lg→300·900 */
...
}
```
### 作为库
```ts
import { generatePalette, toCSSTokens } from 'accessible-color-palette'
const result = generatePalette('#1F7A54', 'white')
// 每个色调包括十六进制、RGB和HSL值
console.log(result.palette['700'])
{
hex: '#1f7a54',
rgb: { r: 31, g: 122, b: 84 },
hsl: { h: 152, s: 59, l: 30 }
}
// 使用地图:对于每个色调,哪些背景色满足普通文本和大文本的要求
console.log(result.usage['700'].normalText)
[
{ key: '100', hex: '#d6f5e8', ratio: 4.18 },
{ key: 'background', hex: '#ffffff', ratio: 5.10 },
...
]
console.log(result.usage['700'].largeText)
[{ key: '300', hex: '#71dbae', ratio: 3.21 }, ...]
// CSS令牌
console.log(toCSSTokens(result))
--color-100: #d6f5e8;
--color-300: #71dbae;
--color-600: #259868;
--color-700: #1f7a54;
--color-800: #10422d;
--color-900: #082116;
// 自定义前缀
console.log(toCSSTokens(result, 'brand'))
--brand-100: #d6f5e8;
// ...
```
### 作为MCP服务器
将它添加到您的MCP客户端配置(Claude Desktop, Cursor等)中——无需安装:
```json
{
"mcpServers": {
"accessible-color-palette": {
"command": "npx",
"args": ["-y", "accessible-color-palette"]
}
}
}
```
或者全局安装并指向二进制文件:
```bash
npm install -g accessible-color-palette
```
```json
{
"mcpServers": {
"accessible-color-palette": {
"command": "accessible-color-palette-mcp"
}
}
}
```
使用MCP服务器有两种方式。
#### 选项A - 直接工具使用
自己调用工具,或让模型自由使用。适用于查询调色板数据或在您控制流程时生成令牌。
| 工具 | 描述 |
| --- | --- |
| `generate_palette` | 返回完整的调色板+使用地图作为JSON |
| `validate_pairings` | 验证前景/背景色调对列表——如果任何对失败,则返回`proceed: false` |
| `generate_css_tokens` | 返回带有每个色调内联WCAG注释的CSS `:root {}`块 |
还有一个资源模板可以直接读取:
```
palette://{hex}/{theme}
```
返回完整的WCAG兼容性矩阵作为JSON——在做出颜色决策之前非常有用。
#### 选项B - 有指导的提示(推荐用于设计任务)
当您将设计任务委派给AI代理时,请使用`plan-palette-usage`提示而不是直接调用工具。该提示注入了严格的4步工作流程:
1. 读取兼容性矩阵(即使在对话中早些时候读取过)
2. 在`<thinking>`块中记录每个计划的颜色配对并检查每个配对
3. 调用`validate_pairings`——模型**被阻止**直到所有配对通过
4. 只有这样,才能调用`generate_css_tokens`
这可以防止模型根据“直觉”或先前的示例组合颜色,这是AI生成的CSS最常见的原因。
**示例指令发送给代理:**
> "使用`plan-palette-usage`提示,十六进制颜色=`1f7a54`,主题=`white`,然后设计一个用户配置文件卡。"
如果没有提示,模型可能会或不会跳过验证。有了它,每个配对都会在编写任何CSS行之前进行验证。
## 输出形状
```ts
interface PaletteResult {
palette: Record<'100' | '300' | '600' | '700' | '800' | '900', {
hex: string
rgb: { r: number; g: number; b: number } // 0–255
hsl: { h: number; s: number; l: number } // h: 0–360, s/l: 0–100
}>
usage: Record<'100' | '300' | '600' | '700' | '800' | '900', {
hex: string
normalText: Array<{ key: string; hex: string; ratio: number }>
largeText: Array<{ key: string; hex: string; ratio: number }>
}>
theme: 'white' | 'black'
sourceColor: string
}
```
- `normalText` - 背景色满足**4.5:1**或更好的要求(正文文本,小UI)
- `largeText` - 背景色满足**3:1–4.49:1**的要求(标题,大文本,图标)
- 未能组合(< 3:1)的组合完全省略
- `key`是一个色调(`'100'`-`'900'`)或`'background'`(白色或黑色,取决于主题)
## 示例输出
**`generatePalette('#1F7A54', 'white')`**
| 色调 | 十六进制 | RGB | HSL |
| --- | --- | --- | --- |
| 100 | `#d6f5e8` | `214, 245, 232` | `152°, 62%, 90%` |
| 300 | `#71dbae` | `113, 219, 174` | `152°, 59%, 65%` |
| 600 | `#259868` | `37, 152, 104` | `152°, 61%, 37%` |
| 700 | `#1f7a54` | `31, 122, 84` | `152°, 59%, 30%` |
| 800 | `#10422d` | `16, 66, 45` | `152°, 61%, 16%` |
| 900 | `#082116` | `8, 33, 22` | `152°, 61%, 8%` |
**`generatePalette('#239062', 'black')`** - 暗主题反转亮度方向
| 色调 | 十六进制 | RGB | HSL |
| --- | --- | --- | --- |
| 100 | `#061911` | `6, 25, 17` | `152°, 61%, 6%` |
| 300 | `#0e3927` | `14, 57, 39` | `152°, 61%, 14%` |
| 600 | `#1c734e` | `28, 115, 78` | `152°, 61%, 28%` |
| 700 | `#239062` | `35, 144, 98` | `152°, 61%, 35%` |
| 800 | `#4fd498` | `79, 212, 152` | `152°, 59%, 57%` |
| 900 | `#b9eed8` | `185, 238, 216` | `152°, 62%, 83%` |
对于`theme: 'black'`,色调100是最暗的。亮度顺序相对于`theme: 'white'`是反转的——这是设计使然。
## 算法工作原理
### 核心原始操作
每个色调都是通过相同的迭代机制找到的:从一个颜色开始,以0.5%的步长调整其HSL亮度,直到与参考颜色的WCAG 2.2对比度达到目标。
```
stepTowardRatio(startHex, referenceHex, targetRatio, direction)
1. 将startHex转换为HSL
2. 每步调整亮度+/- 0.005
3. 每次调整后:计算contrastRatio(current, referenceHex)
4. 当比率 >= targetRatio时停止
5. 安全限制:抛出错误后1000步
```
对比度始终使用**精确的WCAG 2.2公式**计算——没有近似,没有HSL亮度快捷方式。
### 色调派生链
700是锚点。其他一切都源自它(或源自从它派生的色调)。
```
inputHex --> find700 --> shade700 --> find100 --> shade100 --> find600 --> shade600 --> find800 --> shade800
| |
|--> find300 --> shade300 +- (600和800的参考)
|
+--> find900 --> shade900
```
### 决策流程图
```mermaid
flowchart TD
A["输入:颜色+主题(白色|黑色)"]
A --> B["查找700\n4.5:1在背景上"]
B --> C["计算颜色与背景之间的对比度"]
C --> D{"比率 === 5.1:1?"}
D -->|是| Z700["色调700 = 颜色"]
D -->|"白色+比率> 5.1"| E1["添加光,直到比率> 5.1\n如果低于→删除1步"]
D -->|"白色+比率< 5.1"| E2["删除光,直到比率≥5.1"]
D -->|"黑色+比率> 5.1"| E3["删除光,直到比率> 5.1\n如果低于→添加1步"]
D -->|"黑色+比率< 5.1"| E4["添加光,直到比率≥5.1"]
E1 & E2 & E3 & E4 --> Z700
Z700 --> F100["查找100\nilluminate(4.5, 700)[白色]\ndarken(4.5, 700)[黑色]"]
Z700 --> F300["查找300\nilluminate(3.1, 700)[白色]\ndarken(3.1, 700)[黑色]"]
Z700 --> F900["查找900\ndarken(3.1, 700)[白色]\nilluminate(3.1, 700)[黑色]"]
F100 --> Z100["色调100"]
F300 --> Z300["色调300"]
F900 --> Z900["色调900"]
Z100 --> F600["查找600\ndarken(3.1, 100)[白色]\nilluminate(3.1, 100)[黑色]"]
F600 --> Z600["色调600"]
Z600 --> F800["查找800\ndarken(3.1, 600)[白色]\nilluminate(3.1, 600)[黑色]"]
F800 --> Z800["色调800"]
```
### 色调-色调合同
| 色调 | 来源 | 目标对比度 | 方向(白色背景) |
| --- | --- | --- | --- |
| 700 | inputHex | 5.1:1 vs background | 如果太亮则变暗,如果太暗则变亮 |
| 100 | shade700 | 4.5:1 vs shade700 | 变亮 |
| 300 | shade700 | 3.1:1 vs shade700 | 变亮 |
| 600 | shade100 | 3.1:1 vs shade100 | 变暗 |
| 800 | shade600 | 3.1:1 vs shade600 | 变暗 |
| 900 | shade700 | 3.1:1 vs shade700 | 变暗 |
## 设计原则
- **无类**。纯功能性——无`class`,无`new`,无`this`。
- **无突变**。每个函数都返回一个新值。
- **无外部颜色库**。WCAG数学约25行,直接实现。
- **严格的TypeScript**。`strict: true`,带有`HexColor`品牌类型,以防止原始字符串通过API泄漏。
- **纯函数**。相同的输入,相同的输出。唯一的副作用在`src/mcp/server.ts`中。
- **单一责任**。每个函数只做一件事。
## API参考
### `generatePalette(hex: string, theme: 'white' | 'black'): PaletteResult`
主要入口点。接受原始十六进制字符串,带或不带`#`,3或6个字符。对于无效的十六进制字符串,会抛出一个包含无效值的消息的`Error`。
### `toCSSTokens(result: PaletteResult, prefix?: string): string`
从`PaletteResult`生成CSS自定义属性声明。默认前缀为`'color'`。不包装在`:root {}`中——调用者决定放置位置。
## 运行测试
```bash
npm test
npm run test:coverage
```
使用[Vitest](https://vitest.dev/)。集成测试验证已知输出与原始Figma测试用例。
## 构建
```bash
npm run build # tsc -> dist/
npm run mcp # 启动MCP服务器(需要先构建)
```
不需要打包器——库提供ESM,Node原生解析。
## 从v1迁移
v2是完全重写的算法相同,但其他一切都改变了——API不兼容。
**有什么变化:**
- 没有类。v1使用`AccessibleColorPalette.generatePalette(...)`。v2使用命名ESM导出。
- 输出形状不同。v1返回具有`compatibilities`键的色调对象。v2返回`palette`对象和单独的`usage`地图。
- 没有外部依赖。v1使用`colorsys`和`@mdhnpm/color-contrast-ratio-calculator`。v2直接实现WCAG数学。
- 提供MCP服务器与AI助手一起使用。
**v1(旧):**
```js
const AccessibleColorPalette = require('accessible-color-palette')
AccessibleColorPalette.generatePalette('#1c734e', 'black')
// → { "700": { compatibilities: { largeText: [...], smallText: [...] }, hex, rgb, hsl } }
```
**v2(新):**
```ts
import { generatePalette } from 'accessible-color-palette'
generatePalette('#1c734e', 'black')
// → { palette: { "700": { hex, rgb, hsl } }, usage: { "700": { normalText: [...], largeText: [...] } }, theme, sourceColor }
```
v1在npm上仍然可用,版本为`accessible-color-palette@1.x`,但不再维护。
## 致谢
算法由 **Marta Hollingsworth** 提供。库和MCP由 **Cecilia Olivera** 提供。