配色看着清楚其实不合格?做了个对比度检测工具
设计稿上浅灰字配白底,看着挺雅致,实际在手机上或者光线强的地方根本看不清。靠眼睛判断"够不够清楚"很不靠谱,屏幕亮度、色觉差异都会影响。
做了个检测工具:填前景色和背景色,按 WCAG 标准算出对比度,给出 AA、AAA 等级判定。顺带能反推"至少要调到多深才合格"。
一、相对亮度
function srgbToLinear(c) {
const v = c / 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
}
function luminance(hex) {
const [r, g, b] = parseHex(hex);
return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
}
关键在于 sRGB 不是线性的,必须先做伽马校正转到线性空间再算亮度。直接拿 RGB 值加权平均,算出来的对比度会偏。那个 0.03928 是 WCAG 规定的阈值。
三个权重(0.2126、0.7152、0.0722)来自人眼对不同颜色的敏感度,绿色最敏感所以权重最大——这也是为什么纯绿看起来比纯蓝亮得多。
二、对比度和等级
function contrast(a, b) {
const l1 = luminance(a);
const l2 = luminance(b);
const hi = Math.max(l1, l2);
const lo = Math.min(l1, l2);
return Math.round(((hi + 0.05) / (lo + 0.05)) * 100) / 100;
}
function level(c, large = false) {
if (large) return c >= 4.5 ? 'AA' : c >= 3 ? 'AA 大字' : '不合格';
return c >= 7 ? 'AAA' : c >= 4.5 ? 'AA' : c >= 3 ? 'AA 仅大字' : '不合格';
}
公式里两个亮度都加 0.05,是为了避免纯黑(亮度 0)时除零。等级判定里大字体的标准更低(3:1 就够),因为字号大本身就好认。
三、颜色解析
function parseHex(hex) {
const h = String(hex).trim().replace(/^#/, '');
const full = /^[0-9a-fA-F]{3}$/.test(h)
? h.split('').map((x) => x + x).join('')
: h;
if (!/^[0-9a-fA-F]{6}$/.test(full)) throw new Error('颜色格式不合法: ' + hex);
const n = parseInt(full, 16);
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
}
三位简写(#abc)要先展开成六位,否则 parseInt 出来是错的。格式校验放在展开之后,非法输入直接抛错。
四、踩过的坑
第一个坑是直接拿 RGB 算亮度。 前面说的,必须做伽马校正。第一版偷懒没转线性空间,算出来的对比度跟在线工具差一大截,还以为别人算错了。
第二个坑是三位简写没展开。 #fff 被当成 parseInt('fff', 16) = 4095,拆出来的 RGB 是 (0, 15, 255),完全不对。
第三个坑是除零。 纯黑背景亮度为 0,不加 0.05 会得到 Infinity。
第四个坑是大字标准不一样。 一律按 4.5 判会把很多大标题误判成不合格。字号要能选,或者至少说明清楚判的是哪个标准。
第五个坑是半透明色。 rgba(0,0,0,0.5) 的实际颜色取决于它叠在什么上面,工具里要求先把透明色合成成实际颜色再测,不支持直接填带透明度的色值。
第六个坑是对比度不等于可读性。 色盲用户分不清某些颜色组合,即使对比度达标也可能读不出来。工具在结果下面标注了这一点,对比度只是可读性的一个维度,不是全部。
五、小结
配色这事靠感觉判断最容易翻车,尤其是"高级灰"那类低对比度方案。把对比度算出来,不合格就调深一点,比争论好不好看有用。
后来加了自动建议。对比度不合格时,工具把较浅的颜色逐步调深,给出"至少调到某个色值才达标"的建议,比只说不合格有用,省得自己一点点试。
另外支持一次测多组。一个页面往往有好几种文字配色,逐组填太慢,支持一次列出多组前景背景批量算。
还有个功能是预览。把待测配色放到示例文字上看实际效果。数字达标但看着仍不舒服的情况是有的,预览能补上这一层判断。
最后是保存配色方案。测过的存下来下次直接选,不用重新输色值。
还有个功能是历史记录。测过的配色存下来,能看到自己试过哪些方案,避免重复劳动。另外支持显示相对亮度:把两个颜色的亮度值直接列出来,理解对比度是怎么算出来的,比只看一个结果数字清楚。最后是说明:字号、字重、行距同样影响观感,对比度达标不等于一定好读。
另外支持色值格式转换,填 HSL 或者 RGB 也能用,不用先转成十六进制。还有个细节是显示两个颜色的十六进制值,确认输入跟自己想的一致。
还有个细节是支持记住上次的配色,下次打开直接接着调,不用重新输色值。另外支持对不合格的组合直接给出建议色,点一下就替换掉。
- 点赞
- 收藏
- 关注作者
评论(0)