首页
/ freeCodeCamp 应用无障碍实战:用足够对比度避免色觉障碍问题(hsl() 调光法与 WCAG 4.5:1 标准)

freeCodeCamp 应用无障碍实战:用足够对比度避免色觉障碍问题(hsl() 调光法与 WCAG 4.5:1 标准)

2026-09-06 20:37:04作者:董灵辛Dennis

本篇技术指南以 freeCodeCamp 课程体系中「Applied Accessibility(应用无障碍)」模块的挑战题《Avoid Colorblindness Issues by Using Sufficient Contrast》为主体,讲解如何用 CSS hsl() 颜色模型中的亮度(lightness)参数调整前景/背景色对比度,满足 WCAG 推荐的 4.5:1 对比比。读完后,你将能够独立判断一组颜色组合是否达到无障碍标准、理解对比度背后的相对亮度计算原理,并能通过修改 hsl() 第三个参数快速修复低对比度的页面配色。

挑战题在课程体系中的位置

这道挑战题位于课程目录 applied-accessibility 模块 中,属于 Responsive Web Design 超模块下的无障碍主题。从 applied-accessibility.json 中的 challengeOrder 可以看出它在整个模块里的编排意图——它紧跟在《Improve Readability with High Contrast Text》(用高对比度文本提升可读性)之后、《Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information》(谨慎选择承载信息的颜色)之前,三者构成一条完整的学习链:

  1. 前一课解决「灰度对比不足」的问题(浅灰字 #D3D3D3 配白底,对比度仅 1.5:1,需改为深灰 #636363 达到 6:1);
  2. 本课解决「彩色背景下对比度不足」的问题,且专门针对色觉障碍用户;
  3. 后一课进一步处理「相邻色相组合」对色觉障碍用户的辨识困难。

挑战题源文件为 587d778f367417b2b2512aac.md,其 YAML frontmatter 中 challengeType: 0 表示这是一个 HTML/CSS 类型挑战。这一编号体系定义在 packages/shared/src/config/challenge-types.tsconst html = 0;challengeType 为 0 的挑战属于 HTML 类(同文件还包括 js = 1step = 7quiz = 8 等),并由 curriculum/schema/challenge-schema.js 中的 Joi 校验规则 challengeType: Joi.number().min(0).max(33).required() 在课程构建时强制约束取值范围 0~33。

颜色使用引入的两类无障碍问题

挑战题描述部分(--description-- 段)开宗明义:颜色是视觉设计的重要组成部分,但它的滥用会引入两个无障碍问题:

  1. 不能仅用颜色传达关键信息——屏幕阅读器用户「看不见」颜色,因此纯靠颜色区分状态/内容对他们是无效的。前几课已通过「为内容提供文本替代」解决了这一点(例如图片的 alt 文本、描述性链接文字)。
  2. 前景色与背景色必须有足够对比度——色觉障碍(colorblind)用户难以区分某些颜色,通常是在**色相(hue)上混淆,有时也体现在明度(lightness)**上。本课聚焦这第二个问题。

关于对比度标准,文档给出了关键事实:WCAG(Web Content Accessibility Guidelines)推荐的 4.5:1 对比比不仅适用于彩色组合,同样适用于灰度组合。且对比比的计算基础是前景色与背景色的相对亮度(relative luminance)值——这一点与前一课《Improve Readability with High Contrast Text》中「对比比通过比较两种颜色的相对亮度值计算得出,取值范围从同色的 1:1(无对比)到白底黑字的 21:1(最大对比)」的表述一脉相承。

理解这个计算基础,是理解本课操作手法的钥匙:既然对比度由亮度决定,那么调整颜色的亮度就能直接改变对比度——而 hsl() 颜色函数恰好把亮度作为独立参数暴露出来。

hsl() 颜色模型与 shade/tint 手法

挑战题将颜色声明为 CSS hsl() 属性(hue 色相、saturation 饱和度、lightness 亮度)。三个参数各有分工:

  • 第一个参数是色相(0–360 度),决定颜色的「种类」;
  • 第二个参数是饱和度,决定颜色的浓郁程度;
  • 第三个参数是亮度(百分比),决定颜色的明暗。

文档进一步给出了实操经验法则:实际工作中,4.5:1 的对比比可以通过两种互补手段达到——

  • 较深的颜色加黑(shade,加深)
  • 较浅的颜色加白(tint,提亮)

从色轮角度看,蓝、紫红、洋红、红这类颜色的较深色调(darker shades)适合做深色端;橙、黄、绿、蓝绿这类颜色的较亮色调(lighter tints)适合做浅色端。换句话说,「深一端压暗、浅一端提亮」双向拉大亮度差,是达到 4.5:1 最直接的工程手段。

实战:把 2.5:1 提升到 5.9:1

初始代码(seed)

挑战的初始代码(--seed-contents-- 段)是 Camper Cat 的博片样式:绿色调背景配栗色(maroon)文字,对比比只有 2.5:1,远低于标准:

<head>
  <style>
  body {
    color: hsl(0, 55%, 20%);
    background-color: hsl(120, 25%, 35%);
  }
  </style>
</head>
<body>
  <header>
    <h1>Deep Thoughts with Master Camper Cat</h1>
  </header>
  <article>
    <h2>A Word on the Recent Catnip Doping Scandal</h2>
    <p>The influence that catnip has on feline behavior is well-documented, and its use as an herbal supplement in competitive ninja circles remains controversial. Once again, the debate to ban the substance is brought to the public's attention after the high-profile win of Kittytron, a long-time proponent and user of the green stuff, at the Claw of Fury tournament.</p>
    <p>As I've stated in the past, I firmly believe a true ninja's skills must come from within, with no external influences. My own catnip use shall continue as purely recreational.</p>
  </article>
</body>

两个关键颜色的 hsl() 参数拆解如下:

属性 色相 饱和度 亮度 含义
color: hsl(0, 55%, 20%) 0(红色系) 55% 20%(很暗) 深栗色文字
background-color: hsl(120, 25%, 35%) 120(绿色系) 25% 35%(偏暗) 偏暗的绿色背景

操作步骤与目标代码

文档给出的指令非常具体:由于颜色已用 hsl() 声明,**只需修改第三个参数(亮度)**即可轻松调整明暗——

  • background-color 的亮度从 35% 提升到 55%(浅色端提亮,tint);
  • color 的亮度从 20% 降到 15%(深色端加深,shade)。

两端同时向相反方向调整,对比比从 2.5:1 提升到 5.9:1,越过 4.5:1 门槛。目标代码如下(对应文档 --solutions-- 段):

<head>
  <style>
  body {
    color: hsl(0, 55%, 15%);
    background-color: hsl(120, 25%, 55%);
  }
  </style>
</head>
<body>
  <header>
    <h1>Deep Thoughts with Master Camper Cat</h1>
  </header>
  <article>
    <h2>A Word on the Recent Catnip Doping Scandal</h2>
    <p>The influence that catnip has on feline behavior is well-documented, and its use as an herbal supplement in competitive ninja circles remains controversial. Once again, the debate to ban the substance is brought to the public's attention after the high-profile win of Kittytron, a long-time proponent and user of the green stuff, at the Claw of Fury tournament.</p>
    <p>As I've stated in the past, I firmly believe a true ninja's skills must come from within, with no external influences. My own catnip use shall continue as purely recreational.</p>
  </article>
</body>

注意色相(0 与 120)和饱和度(55% 与 25%)都没有改动——这正是本课刻意设计的教学点:修复对比度优先动亮度,而不是换色相,因为对比度本质上就是亮度差的函数。

测试断言:对比度如何被自动验证

该挑战的 --hints-- 段给出了两条基于正则表达式的代码校验断言(freeCodeCamp 用 Chai 风格 assert 对学员提交代码做匹配),它们精确定义了「做对了什么」:

// 断言 1:文字 color 属性的亮度必须改为 15%,其余参数保持 0 与 55%
assert.match(code, /color:\s*?hsl\(0,\s*?55%,\s*?15%\)/gi);
// 断言 2:背景 background-color 属性的亮度必须改为 55%,其余参数保持 120 与 25%
assert.match(code, /background-color:\s*?hsl\(120,\s*?25%,\s*?55%\)/gi);

从这两条断言的结构可以读出课程验收逻辑:

  • 正则用 \s*? 容忍任意空白,说明允许学员自由排版;
  • 三个数值参数全部锁定0, 55%, 15%120, 25%, 55%),意味着色相、饱和度不许改动,只允许动亮度——这与文档「只改第三个参数」的指令严格一致;
  • 使用 /gi 标志做大小写不敏感的全局匹配。

与前后的衔接:三色组合策略

同模块相邻的下一课 587d778f367417b2b2512aad.md(谨慎选择承载信息的颜色)补充了本课未展开的另一维度:即便对比度达标,色轮上相邻的色相组合(例如黄色底 #FFFF33 配绿色字 #33FF33)对色觉障碍用户仍然难以区分。该课指出最常见的色觉障碍形式是「对绿色的敏感度降低」,并要求把按钮文字改为深蓝 #003366 来同时解决色相邻近与亮度接近两个问题,还建议借助支持色觉障碍仿真的在线取色工具辅助决策。

对照 Improve Readability with High Contrast Text 一课,三课可以归纳出一套可复用的配色检查清单:

  1. 亮度差达标:正常文本对比比 ≥ 4.5:1(WCAG 推荐值),可用在线对比度检查工具计算;
  2. hsl() 微调:颜色以 hsl() 声明时,直接拉大前景/背景的第三参数差值(深者更暗、浅者更亮),本课 20%→15% 与 35%→55% 即为例证;
  3. 色相不邻近:承载信息的颜色避免选择色轮上的相邻色,尤其是绿色系之间的细微差别;
  4. 颜色不作唯一通道:关键信息必须有文本替代,保证屏幕阅读器用户可用。

小结

本课的核心技术资产是:以 WCAG 4.5:1 对比比为准绳、以相对亮度为计算基础、以 hsl() 第三参数为调节旋钮,配合 shade/tint 双向拉大亮度差(2.5:1 → 5.9:1)的完整修复流程,并由正则断言保证学员只改亮度、不动色相与饱和度。这套「声明式颜色 + 单一参数微调」的手法在真实项目中同样适用:只要设计稿以 HSL 或 HSLA 交付颜色,修复低对比度问题通常无需重选颜色,只需系统性地拉开明度差,再用对比度工具复核即可。

登录后查看全文
热门项目推荐
相关项目推荐