使用方法
- 页面打开时已经是示例色
#FF0000(纯红),拾色器、HEX 框、R / G / B 三个框、结果卡和下面的「完整示例」用的是同一个值,可以直接对照。 - 换色有三种方式:拖拾色器、在 HEX 框输入
#RRGGBB(如#315FE8)或三位缩写#RGB(如#F0A)、或在 R / G / B 三个框里各填 0~255 的整数。三处任意一处改动,其余两处自动同步。 - 看结果卡:相对亮度 L 是 WCAG 用来算对比度的中间量,线性 RGB 是 sRGB 做 gamma 反变换后的值,与黑 / 与白 两行给出这个颜色与纯黑、纯白的对比度。
- 看建议正文字色:工具取「与黑」「与白」中对比度较大的那个作正文色。示例色
#FF0000建议#000000,5.25:1,下面的预览块会按它真实渲染一段文字。 - 最下方的「混色演示」把当前色与白色各取一半,分别用「直接在 sRGB 上混」和「先线性化再混」算一遍,用来直观看出 gamma 的影响;点「复制全部色值」可把 9 张卡一次性带走。
这个颜色选择器能解决什么问题
一是判断文字压在底色上能不能看清。设计稿定了主色,正文用黑字还是白字凭眼睛看经常出错:中灰就是典型,#767676 上黑字 4.62:1、白字 4.54:1,都刚过 AA 线;再深一级的 #777777 上白字掉到 4.48:1 就不合格。本页把两个数字并排列出并给出建议值。
二是把三位缩写正确展开。从设计稿或旧代码里抄来的 #F0A、#ABC 这类缩写,展开规则是把每一位复制成两位:#F0A 是 #FF00AA,不是 #F0A000。规则写反了颜色会整体跑偏,本页输入缩写后会直接显示展开结果并给出提示。
三是解释「手动调浅以后颜色发灰」。把颜色和白色各取一半,结果比预期暗且发灰,原因是直接用 sRGB 编码值做算术、跳过了线性化。原理一节给出的实测差异是 #808000 与 #BCBC00,相对亮度差一倍以上。
四是快速核对无障碍阈值:某个色值对是否达到 4.5:1(正文)、3:1(大字与非文本)、7:1(AAA 正文)。本页把这三档判定直接写在结果里,完整的阈值对照表放在下面一节。
本页不做这些事:不检测成对的两种颜色(需要分别输入前景与背景并出具合规报告)——那请用颜色对比度检测;不打印 CMYK、不做印刷色转换——那是十六进制转RGB之外的专门页面负责;不生成互补色、邻近色等配色方案——请用互补色颜色查询;也不从图片里吸色,那是图片颜色取色。
sRGB、线性 RGB 与相对亮度:为什么必须先做 gamma 反变换
这个颜色选择器内部做的第一件事不是取颜色,而是把十六进制值拆成三个 0~255 的整数,并认定它们属于 sRGB 编码空间。日常写在 CSS 里的 #FF0000 就是 sRGB 编码值,它按 IEC 61966-2-1 定义的分段函数缩放:归一化通道值 c 不大于 0.04045 时,线性值是 c / 12.92;超过 0.04045 时,线性值是 ((c + 0.055) / 1.055) 的 2.4 次方。反过来的函数阈值是 0.0031308,小于等于它时乘以 12.92,大于它时用 1.055 乘 c 的 1 / 2.4 次方再减 0.055。
为什么不能跳过这一步。因为 sRGB 编码值不是线性的「光强比例」,而是做过非线性压缩的编码。把 #FF0000 与 #00FF00 各取一半:直接在编码值上平均得到 #808000,相对亮度 0.1986;先线性化、再平均、再编码回 sRGB 得到 #BCBC00,相对亮度 0.4639,差了 1.34 倍,肉眼就是「灰暗」与「明亮」的差别。单通道更极端:sRGB 的 0.5(128/255)对应线性值只有 0.2140,而线性空间的 0.5 编码回 sRGB 是 0.7354(188/255)——这正是分段函数中段最陡的原因。混色、渐变与亮度计算都必须先做 gamma 反变换。
相对亮度怎么算。WCAG 2.1 的公式是 L = 0.2126R + 0.7152G + 0.0722B,R、G、B 必须已经线性化并归一化到 0~1。三个系数来自 Rec.709 亮度权重,反映人眼对绿最敏感、对蓝最迟钝:纯绿 #00FF00 的 L 正好是 0.7152,纯红 0.2126,纯蓝 0.0722,纯黑 0,纯白 1。旧代码常见的 0.299 / 0.587 / 0.114 是 Rec.601 系数,套进 WCAG 口径是错的。
对比度怎么算。两个颜色的相对亮度记为 L1、L2,取较亮的作分子、较暗的作分母,对比度是 (L1 + 0.05) / (L2 + 0.05)。这个 + 0.05 是规范固定写死的偏移量,用来模拟屏幕表面的环境光反射,并避免纯黑背景时除零。黑白代进去就是 (1 + 0.05) / (0 + 0.05) = 21,所以 WCAG 对比度的量程是 1:1 到 21:1,超过 21 一定是公式写错了。
AA / AAA 的适用场景不一样。AA 的正文字号门槛是 4.5:1,大号文字只要 3:1;大号的定义是 18pt(约 24px)以上,或 14pt(约 18.66px)以上且加粗。AAA 更严:正文要 7:1,大号也要 4.5:1。另有 AA 的 1.4.11 要求非文本元素(图标、边框、开关、图表色块)与相邻颜色的对比度不低于 3:1。同一个 #FF0000,与白底 4.00:1,做正文不合格、做 24px 标题合格;与黑底 5.25:1,做正文合格。
HSL 与 sRGB 的转换不是无损几何关系。色相 H 是 0~360 的角度,每 60 度一段落在六个扇区;饱和度 S 与亮度 L 是百分比。用整数度的 H、整数百分比的 S / L 表示再转回 RGB,会因为四舍五入丢信息。实测把 #315FE8 转成 hsl(225, 80%, 55%) 再转回来得到 #305EE8,蓝通道差 1 级;256 个灰度逐一走一遍「HEX 到 HSL 取整再回 HEX」,有 155 个对不上,最大偏差 1 级。所以 HSL 适合调参,不适合当存储格式。
完整示例(数值仅作演示)
这个颜色选择器的示例条件与页面打开时的默认值完全一致:色值 #FF0000,即 RGB(255, 0, 0)。把它代进上面三条公式,逐步算一遍:
- 线性 RGB:三个通道归一化后是 1.0000、0.0000、0.0000,都已经落在分段函数的线性端,所以线性值就等于自身。
- 相对亮度 L:
0.2126 × 1 + 0.7152 × 0 + 0.0722 × 0 = 0.2126。 - 与黑
#000000(L = 0):(0.2126 + 0.05) / (0 + 0.05) = 5.25,达到 AA 正文线,未达 AAA 的 7:1。 - 与白
#FFFFFF(L = 1):(1 + 0.05) / (0.2126 + 0.05) = 4.00,低于 4.5 的正文线,但高于 3:1,可以用于大字、图标和边框。 - 建议正文字色:黑的 5.25 大于白的 4.00,所以推荐
#000000,预览块就按黑字渲染。 - HSL:
hsl(0, 100%, 50%);再转回 HEX 仍是#FF0000,这一档是少数几个能精确往返的取值之一。 - 与白色各 50% 混合:直接在 sRGB 上混得到
#FF8080(L = 0.3811),先线性化再混得到#FFBCBC(L = 0.6063),后者亮度是前者的 1.59 倍。想做「提亮 / 调浅」,正确的那条是右边这个。
需要强调:这几个数字都是拿 8 位整数通道算出来的固定值,不依赖屏幕、系统或浏览器。你在自己的页面上把 #FF0000 填进去,得到的会是同一组数。
色值、相对亮度与对比度对照表
下表所有数字都由上面的公式逐项算出,保留两位小数。看这张表能快速建立直觉:同样是「纯色」,绿底黑字有 15.30:1,蓝底黑字只有 2.44:1——因为绿的亮度权重是蓝的将近 10 倍。
| 色值 | 相对亮度 L | 与黑 #000000 | 与白 #FFFFFF | 正文字色建议 |
|---|---|---|---|---|
| #000000 纯黑 | 0.0000 | 1.00:1 | 21.00:1 | 白字(21.00:1) |
| #FFFFFF 纯白 | 1.0000 | 21.00:1 | 1.00:1 | 黑字(21.00:1) |
| #FF0000 纯红(默认) | 0.2126 | 5.25:1 | 4.00:1 | 黑字(5.25:1) |
| #00FF00 纯绿 | 0.7152 | 15.30:1 | 1.37:1 | 黑字(15.30:1) |
| #0000FF 纯蓝 | 0.0722 | 2.44:1 | 8.59:1 | 白字(8.59:1) |
| #315FE8 品牌蓝 | 0.1466 | 3.93:1 | 5.34:1 | 白字(5.34:1) |
| #767676 中灰(压线通过) | 0.1812 | 4.62:1 | 4.54:1 | 黑字(4.62:1) |
| #777777 中灰(压线不通过) | 0.1845 | 4.69:1 | 4.48:1 | 黑字(4.69:1) |
| #808080 中灰 | 0.2159 | 5.32:1 | 3.95:1 | 黑字(5.32:1) |
下面这张表把 AA / AAA 的字号门槛和适用场景列在一起,判定结果就是结果卡里显示的那一档:
| 条目 | 正文(小于 24px) | 大字(≥ 24px 或 ≥ 18.66px 粗体) | 非文本(图标 / 边框 / 控件) |
|---|---|---|---|
| AA(1.4.3 与 1.4.11) | 4.5:1 | 3:1 | 3:1 |
| AAA(1.4.6) | 7:1 | 4.5:1 | 不适用 |
三位缩写的展开规则单独列一张表。关键点是把每一位复制成两位,而不是在右边补零:
| 三位缩写 | 正确展开(复制半字节) | 错误写法(整体右补零) |
|---|---|---|
| #F0A | #FF00AA | #F0A000 |
| #ABC | #AABBCC | #ABC000 |
| #123 | #112233 | #123000 |
| #F00 | #FF0000 | #F00000 |
| #FFF | #FFFFFF | #FFF000 |
输入范围、边界与精度说明
- HEX 只接受 3 位或 6 位十六进制,可带
#也可不带,大小写不敏感。#12345这种 5 位、8 位的#RRGGBBAA(含透明度)都会被拒绝并给出提示——本页不做 alpha 合成。 - R / G / B 三个框必须是 0~255 的整数,小数、字母、空值和越界值都会被拒绝,报错里会写出你实际填的内容。十六进制本质上也是这三个整数,两条输入路径等价。
- 对比度保留两位小数,但判定用未舍入的原值:
4.4999显示成4.50,仍判为不通过。纯白底上要让对比度刚好等于 4.5,需要 L 落在 0.18333 附近,而 8 位通道能取到的 L 是离散的,只有少数色值能精确命中。 - 8 位通道只有 256 级,L 会撞车。两个不同的 RGB 三元组可能算出同一个 L,所以「亮度一样」不代表「颜色一样」。
- 这个颜色选择器算的是标准 sRGB 下的数值。显示器工作在宽色域(Display-P3)且未做色彩管理时,你看到的颜色与公式里的数值会不一致;色域映射属于另一套流程,不在本页范围内。
- 观感差异不等于计算错误。屏幕亮度、环境光和涂层都会影响实际可读性;WCAG 的阈值是下限要求,达标不等于舒适,不达标也不代表一定看不清。
- HSL 往返显示的是「能不能回到原值」。结果卡里如果与原色不同,说明把 HSL 取整成整数后再转回 RGB 丢了 1 级精度,这不是 bug,而是整数化本身的信息损失。
- 首屏结果区是服务端直出的。页面 HTML 里已经写好了
#FF0000的 9 张卡,即使脚本没有执行也能看到示例;改动任意一个输入框后,卡片才由脚本重算。
常见问题
为什么红字白底只有 4.00:1?红不是很「跳」吗?
红看起来醒目,靠的是色相差异而不是亮度差异。#FF0000 的相对亮度只有 0.2126,白底是 1,代入公式得到 4.00,差 0.5 落到 AA 正文线之下。要当正文用就把红调深(例如 #CC0000 附近),或者只把它用在 24px 以上的标题——大字门槛 3:1,4.00 够用。
我直接用 (R + G + B) / 3 当亮度不行吗?
不行,两处都错。权重不该等分(绿 0.7152、红 0.2126、蓝 0.0722),而且必须先做 gamma 反变换。实测 #0000FF 的朴素均值是 0.3333,WCAG 相对亮度只有 0.0722,差 4.6 倍——按均值判断会把蓝底黑字误判成合格。旧代码里的 0.299 / 0.587 / 0.114 是 Rec.601 系数,与 WCAG 用的 Rec.709 不是一套。
#F0A 展开成 #FF00AA,为什么不是 #F0A000?
三位缩写的语义是「每一位代表一个通道」,不是「省略了后三位」。#F0A 的 F 是红、0 是绿、A 是蓝,各复制成两位得到 #FF00AA;右补零变成 #F0A000,红通道 F0、绿通道 A0,颜色从品红跑成暗黄绿。
为什么 #FF0000 的 HSL 转回来是原值,别的颜色就不是?
因为纯色(L 恒为 50%、S 恒为 100%)与灰阶(S 恒为 0%)恰好能对上原整数。S 或 L 一旦落在中间档,整数百分比就表示不了原通道值,回程出现 1 级误差。实测 7 个常见色里只有 #FF0000 完全一致;256 个灰度里有 155 个对不上。
黑白的对比度为什么正好是 21?
代入公式即得:黑 L = 0、白 L = 1,(1 + 0.05) / (0 + 0.05) = 21。相对亮度的取值是闭区间 [0, 1],所以任何一对颜色的对比度都落在 1:1 到 21:1 之间。看到超过 21 的数字,基本可以确定是公式写错了。
为什么有时候黑字白字都不达标?
看「与黑」「与白」两行:都不到 4.5 就说明底色落在中亮度陷阱里,典型是 #7F7F7F 一类中灰。正确做法不是硬凑文字色,而是把底色朝黑或朝白挪一点,让其中一个方向回到 7:1 以上。
为什么这里的对比度和设计软件里显示的不一样?
先确认口径。常见分叉有三个:用了 Rec.601 的系数而不是 Rec.709;忘了对 sRGB 做 gamma 反变换,直接拿 0~255 的编码值加权;先把 alpha 通道做了合成。本页固定用 WCAG 2.1 口径,中间量(线性 RGB、L)都列了出来,可手工复核。
相关工具
- 颜色对比度检测:把前景色与背景色分别输入并出具完整判定,本文末尾提到的成对检查用这个。
- 十六进制转RGB:只做 HEX 与 RGB 之间的换算,需要批量对照时比本页更轻。
- RGB转HSL转换器:专做 RGB 与 HSL 的互转,可以拿来验证本页的往返误差样例。
- 互补色颜色查询:按色相环反查互补色,定强调色时用。
- 十六进制颜色表:按色系列出常用十六进制色值,挑基准色时比逐个试快。
- WebSafeColors图表:216 色网页安全色表,做兼容性要求较老的项目时用得上。
- 图片颜色取色:从图片里吸取像素颜色,拿到色值后可以再回到本页算对比度。
- 颜色工具:查看全部颜色工具。