配色看着清楚其实不合格?做了个对比度检测工具

举报
茉莉风铃 发表于 2026/10/15 12:55:09 2026/10/15
【摘要】 浅色配浅底看着雅致实际看不清,做了个按 WCAG 标准算对比度的检测工具。讲了必须先做伽马校正转线性空间再算亮度、三位简写色值要先展开、纯黑除零需加 0.05、大字号标准更低、半透明色需先合成、以及对比度达标不等于对色觉障碍用户可读。

设计稿上浅灰字配白底,看着挺雅致,实际在手机上或者光线强的地方根本看不清。靠眼睛判断"够不够清楚"很不靠谱,屏幕亮度、色觉差异都会影响。

做了个检测工具:填前景色和背景色,按 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 也能用,不用先转成十六进制。还有个细节是显示两个颜色的十六进制值,确认输入跟自己想的一致。
还有个细节是支持记住上次的配色,下次打开直接接着调,不用重新输色值。另外支持对不合格的组合直接给出建议色,点一下就替换掉。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。