调色工具

调色调配加对比度校验,两件事一起做:拖动 HSL 三个滑块找色,同时按 WCAG 2.x 的相对亮度公式算出它对白、对黑的对比度,直接标出 AA 正文 4.5、AA 大字 3、AAA 7 三档是否达标;不达标时反解出明度该调到多少才过线。

明度 L色块HEX对白对比度对黑对比度建议文字色

提示:在任意输入框里按 Enter 即可重算。HEX 支持 #315FE8、315fe8、#F0F 三位缩写与 rgb(49,95,232) 四种写法,非法值会指出错在哪一位。

使用方法

  1. 在「HEX 颜色值」里填色号,示例填 #315FE8;也可以直接点左边的方块用系统取色器挑。三个滑块会跟着联动,你拖哪一边都会同步回写这个框。
  2. 在「对比度目标」里选标准档位,示例选 AA 正文 4.5:1。三个可选值就是 WCAG 2.1 里最常用的三档,选它只影响「反解达标明度」按钮的目标线,不影响对比度本身。
  3. 点「计算对比度」,或按 Enter,结果区立刻给出这个色的 rgb(49, 95, 232)、HSL(225° / 79.9% / 55.1%)、相对亮度 0.146636,以及对白 5.34:1、对黑 3.93:1。
  4. 看三枚达标徽标:示例色对白是 5.34:1,过 AA 正文 4.5:1(绿标),对黑只有 3.93:1,卡在 AA 大字 3:1 与 AA 正文 4.5:1 之间(黄标)。
  5. 如果不满意,点「反解达标明度」,页面会保持你的色相和饱和度不动,告诉你明度该调到多少才过目标线;下方 20 行明度阶梯表可以逐档核对,CSV 导出带 BOM。

这个调色工具能解决什么问题

做界面时最难判断的一件事是「这个颜色配白字还是配黑字」。看着差不多的两个灰,落到 16px 正文上,一个清楚一个糊成一团;不对比一下根本看不出来。调色工具把这件事变成一次可计算的判断:给定一个前景色,立刻告诉你它和纯白、纯黑各自的对比度,以及过不过 AA 那一档。

第二个场景是改色不改品牌。品牌主色是定了的,但用在深色背景上不够清楚、用在浅色背景上又太刺眼。真正的解法往往不是换色相(换了就变品牌了),而是只调明度,保持色相与饱和度不变,让这个色在深浅两种背景上都找到能过线的那一档。本页的「反解达标明度」就是干这个的。

第三个场景是排查设计稿的可访问性问题。设计给了一版配色,你想知道按钮文字、输入框边框、图标这几个位置到底卡在哪一档。调色工具把三枚徽标(AA 正文 4.5、AA 大字与非文本 3、AAA 7)分别标出来,能一次看完,不用逐个心算;下方 20 行明度阶梯表还会把「白字 / 黑字 / 都不达标」的分界线直接画在行上。

本页不做的事要划清。只想看颜色叫什么名字,那是颜色名字查询,不是本页;想把 HEX 和 RGB 互转,那是两个独立的单功能转换器,本页的结果区虽然会显示两种写法,但主功能是校验不是转换;想要一整套配色方案、邻近色或互补色配色,那是颜色配色方案生成器,本页只处理单个颜色的明度与对比度;想从图片里吸色,那是图片颜色取色。另外,本页算的是 WCAG 2.x 相对亮度对比度,不是 APCA(WCAG 3 草案里的新算法),两者在深色底与细字号的判定上有差异,需要 APCA 结果请用专门页面。

原理与规则说明

对比度公式来自 WCAG 2.1 / 2.2 的相对亮度定义,三步:

// 1) 每个通道线性化(sRGB 反伽马)
c = v / 255
lin = c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ^ 2.4
// 2) 相对亮度
L = 0.2126 * lin(R) + 0.7152 * lin(G) + 0.0722 * lin(B)
// 3) 对比度
ratio = (max(L1, L2) + 0.05) / (min(L1, L2) + 0.05)

三个系数 0.2126 / 0.7152 / 0.0722 不是随便取的,它们是 sRGB primaries 在 D65 illuminant 下的相对亮度加权,绿色权重最大是因为人眼对绿色最敏感。整条链的规范出处是 W3C 的 Web Content Accessibility Guidelines 2.1 成功准则 1.4.3(对比度最低)与 1.4.11(非常规文本对比度),国内等同要求见 GB/T 37668-2019《信息技术 互联网内容无障碍可访问性技术要求与测试方法》。

为什么必须先线性化。0.2126/0.7152/0.0722 这套权重是定义在线性光上的,直接拿 sRGB 的 0~255 数值去加权是错的 —— 那等于把伽马编码又算了一遍。分界点 0.03928 是规范里写死的常量(而不是常见的 0.04045,那是另一版反伽马算法的阈值,差异出现在极暗的通道上)。示例色 #315FE8 的三个通道线性化后是 0.030713 / 0.114435 / 0.806952,加权得 0.146636 —— 注意蓝色通道贡献了 0.0722 × 0.806952 = 0.0583,占总亮度的四成,这就是它虽然最亮却不是最亮的原因。

+0.05 这个偏移不能省。它来自韦伯-费希纳定律的视觉模型:纯黑与纯黑的对比度按公式算是 0/0,实际观察到的黑底黑字完全看不见,所以规范在分子分母各加 0.05 做平滑。这也直接决定了公式的上限是 21:1 —— 纯白对纯黑是 (1+0.05)/(0+0.05) = 21,永远不会超过 21。看到有工具报出 40:1 或者 100:1,那不是更准,是算错了。

HSL 三个分量的取舍。调色工具把色相 H 定为 0~360 的整数,饱和度与明度给到 0.1% 的步进。为什么明度要细到 0.1%:临界点上 0.5% 的明度差就能让对比度跨过 4.5:1 这条线,举个实测例子,色相 225°、饱和 79.9% 的这一族颜色里,明度 58% 的 #3E69E9 对白是 4.77:1(达标),明度 60% 的 #4770EB 是 4.39:1(不达标)—— 差 2% 明度,结论就反了。色相反而不给小数,是因为 1° 的色相变化在明度固定时对相对亮度的影响极小,没必要浪费精度。

阈值的三档具体是什么,这是必须写清的:

实测的临界中性灰能把这三档的严肃性看出来:对白要过 4.5:1,最亮的中性灰是 #767676(4.542:1),再亮一档 #777777 就掉到 4.478:1,不达标了。对白过 3:1 的最亮灰是 #949494(3.033:1),再亮一档 2.995:1 同样不达标。所以「灰色文字」这件事在设计上是有硬边界的,#888 恰好落在两者之间。中文网页常用的 #999 对白只有 2.85:1,连大号文字都不达标。

反解明度用的是什么方法。保持 H 和 S 不动,只改 L,然后对 L 做单调步进搜索:0.1% 为一步,从当前 L 出发朝能改善对比度的方向走,走到第一个满足目标线的 L 就停。之所以用步进而非二分,是因为 sRGB 空间的 L 与 WCAG 相对亮度之间不是严格单调的线性关系(HSL 的 L 是 (max+min)/2,和 WCAG 亮度定义完全不同),二分的单调性前提不成立。这个设计的代价是保持色相,但代价换不来的是风格不跑偏 —— 换成降饱和度也能过线,但那样颜色就「脏」了。

完整示例(数值仅作演示)

示例条件:HEX #315FE8,校验背景 #FFFFFF,目标档 AA 正文 4.5:1。逐项算下来:

这组数字与下方对照表是同一套算法产出的:明度 55% 那一行的 #315FE8 正是这个色,明度 58% 的 #3E69E9 对白 4.77:1 达标、再往下到 60% 的 #4770EB 对白 4.39:1 不达标,边界就在 58% 与 60% 之间。文字里说的「5.34」和表里的「5.34」是同一个数。以上数值仅作演示,不构成任何合规结论 —— 正式的无障碍验收需要人工测试辅助技术实测。

输入范围与对照表

下表固定你当前的色相与饱和度,把明度从 10% 逐档推到 100%,共 20 行,让你看清对比度随明度单调变化的形状,以及「白字 / 黑字 / 都不达标」的分界线落在第几行。表格默认显示 12 行,点「加载更多」展开全部 20 行,也可导出 CSV(带 BOM)。当前颜色的明度所在行会高亮。

明度 L色块HEX对白对比度对黑对比度建议文字色
10%#050F2E18.85:11.11:1#FFFFFF
15%#08174517.23:11.22:1#FFFFFF
20%#0A1F5C15.40:11.36:1#FFFFFF
25%#0D267313.62:11.54:1#FFFFFF
30%0F2E8A11.81:11.78:1#FFFFFF
35%#1236A110.15:12.07:1#FFFFFF
40%#143DB88.79:12.39:1#FFFFFF
45%#1745CE7.56:12.78:1#FFFFFF
50%#1A4DE56.49:13.24:1#FFFFFF
52%#2354E66.03:13.48:1#FFFFFF
55%#315FE85.34:13.93:1#FFFFFF
58%#3E69E94.77:14.40:1#FFFFFF
60%#4770EB4.39:14.79:1#000000
65%#5E82ED3.56:15.89:1#000000
70%#7594F02.90:17.25:1#000000
75%#8CA6F22.37:18.85:1#000000
80%#A3B8F51.96:110.73:1#000000
85%#BACAF71.63:112.88:1#000000
92%#DAE2FB1.29:116.25:1#000000
100%#FFFFFF1.00:121.00:1#000000

上表的色相与饱和度固定为 H = 224.9°、S = 79.9%,也就是默认示例那一族。读表要点:对白对比度随明度单调下降、对黑单调上升,两条曲线在 58% 与 60% 之间交叉于 4.5:1 附近 —— 交叉点就是「白字还是黑字」的分界,交叉之后建议改用黑字。整张表里没有任何一行出现「都不达标」,那是因为白与黑总能挑出一个 4.5:1 以上的;真正会两边都不达标的,是背景与前景都取中间调子的情况。

输入范围、边界与精度说明

常见问题

为什么对比度最高只能到 21:1,不是无限大?

因为公式的分母里那个 +0.05。纯黑对纯黑在数学上是 0/0,规范为了模拟「黑底黑字完全看不见」这个事实,在分子分母各加 0.05 做平滑,于是上限被锁定在 (1+0.05)/(0+0.05) = 21。实测纯白 #FFFFFF 对纯黑 #000000 正好是 21.00:1。这也说明超过 21 的对比度在无障碍层面没有额外意义,业界不再区分 21 和 100。

WCAG 3 的 APCA 算出来和这个不一样,该信哪个?

两个都算,但用途不同。WCAG 2.x 的相对亮度对比度是现行标准(WCAG 2.1 和 2.2 都用它),法规与合规审计仍以它为准。APCA 是 WCAG 3 草案引入的新模型,在深色主题、细字重、半透明层叠这些场景下更符合实际观感,但目前还不是推荐标准。所以:对外要合规证明用 2.x,做深色主题的精细调校可以看 APCA。本页给的是 2.x 口径,不提供 APCA 结果。

我的品牌色改明度之后还是不满意,还有别的办法吗?

有三条路,按推荐顺序:一是改背景而不是改前景,很多场景下主色是固定的、可变的是底色,把底色压到 L=10% 附近,主色不用动就过了;二是降低饱和度,深色主题里降低饱和度能提亮而不刺眼,代价是颜色变「灰」,品牌感会弱一些;三是换色相,这个代价最大,通常意味着换品牌色。本页只提供第一条路里的「调背景」和「调前景明度」两种,因为它们不引入第三方库就能算准。

中文字号怎么算「18pt」?CSS 里的 px 和它什么关系?

规范用 pt,浏览器用 px。换算基准是 1pt = 1/72 英寸,在 CSS 的 96dpi 假设下 1pt = 96/72 = 1.3333px。所以 18pt = 24px,14pt = 18.67px。这条界线对中文页面影响不小:14px 的中文正文按规范属于「小字」,必须 4.5:1;而 24px 以上才算「大号」,可以用 3:1。也就是说中文网页里几乎所有正文都该按 4.5:1 来做,别拿 3:1 给自己放宽。

图标和边框也要 4.5:1 吗?

不要,这是最常见的误用。非常规文本(成功准则 1.4.11)的门槛是 3:1,适用对象是:UI 控件的边界、输入框边框、图标、图表的线条与色块、状态指示灯。判定对象是「这个元素与它相邻颜色的对比」,不是与纯白纯黑 —— 一个浅灰按钮在白底上只需要 3:1,因为它要让人看出边界在哪,而不是读懂内容。用 4.5:1 去卡图标会做出很难看的界面,而用 3:1 去卡正文则会牺牲可读性,两者正好搞反。

半透明背景怎么算?

先合成再算。半透明前景色要先和它背后的实际颜色做 alpha 混合,得到不透明的等效 RGB,再套亮度公式。同理,文字压在图片上时,图片那部分的颜色得逐处采样 —— 这正是图片取色工具的用途。本页只处理纯色,填 #RRGGBBAA 八位形式会被拒绝并提示「本页只接受六位 HEX,半透明请先与背景色手动合成」,因为 alpha 合成需要知道背后到底是什么色。

表格里「建议文字色」那一列是怎么判的?

规则只有一条:看对白与对黑哪个的对比度高,就建议哪个,同时要求它至少过 4.5:1。58% 那行对白 4.77 高于对黑 4.40,所以建议 #FFFFFF;60% 那行对黑 4.79 高于对白 4.39,翻转成 #000000。这一列的价值在于省掉你逐行心算,尤其在明度 58% 到 60% 这种两条曲线刚交叉的区间里,人眼判断非常不准。

这个页面会把颜色值发到别处吗?

不会。全部计算是三次 Math.pow 加两次乘加,加上一次 HSL 二分转换,没有 fetch、没有 XHR、没有第三方库。你可以在开发者工具的 Network 面板确认页面加载后不再有任何请求,刷新一下颜色就清空了。唯一的输入是 HEX 和几个滑块的数值,它们本来也不是敏感信息。

相关工具