08无障碍访问

无障碍(a11y)= 让所有人都能用上你的网页,包括看不见屏幕的人、 用不了鼠标的人。好消息是:做好它基本不需要额外成本, 大多数时候只需要一件事——用对标签。

约 15 分钟 6 个动手实验 人人受益

一、什么是无障碍(a11y)

a11y 是 accessibility 的数字缩写:首字母 a 和尾字母 y 之间 夹着 11 个字母,写全太累,于是大家约定俗成叫它 a11y(读作 "ally",盟友——挺贴切)。

谁需要无障碍?远比你想象的多:

视障用户 看不见屏幕,靠屏幕阅读器把页面「读」出来听。 屏幕阅读器
听障用户 听不见视频和语音,靠字幕、文字稿获取信息。 字幕 / 文字稿
运动障碍用户 用不了鼠标,全程只靠键盘 Tab 键操作页面。 纯键盘
情境障碍用户 阳光直射看不清屏、单手抱娃腾不出手、地铁里没信号。 每个人都可能遇到

最后这类「情境障碍」指向一个重要观点:无障碍让所有人受益。 城市里的轮椅坡道,推行李箱的、推婴儿车的、骑滑板车的都在用—— 这就是著名的「路缘坡效应」:为少数人做的设计,最后方便了每一个人。

人行道
马路
金色斜坡 = 路缘坡:为轮椅修的,但行李箱、婴儿车、滑板车都爱走它
屏幕阅读器可以想象成一个「读屏的速读员」:它不看画面, 只读 HTML 结构,然后用语音念给用户听。常见软件有 Windows 免费的 NVDA、 Mac / iPhone 自带的 VoiceOver。你写的标签就是它唯一的「眼睛」。

二、语义化是无障碍的地基

还记得第 06 课的语义化吗?它就是无障碍的地基。屏幕阅读器靠 <nav>、<main>、标题层级这些语义标签 「读」出页面结构:用户可以直接说「跳到导航」「跳到正文」 「列出所有标题」。如果全页都是 div,速读员拿到的是一锅粥——每一口都一样,没有目录可跳。

同一个小站,左右两种写法(渲染效果可以一样,读屏体验天差地别):读两边代码,数一数右边有几个「地标」是左边没有的
屏幕阅读器眼里的两种写法:同一页面的两种「朗读体验」
页面区域div 汤读起来语义化读起来
导航区「分组……一堆链接」(不知道是导航)「导航,地标」→ 可一键直达 / 跳过
主内容和侧栏、页脚混在一起,无从分辨「主要内容,地标」→ 说「跳到正文」就到
标题和普通文字一个待遇,没有层级「标题,级别 2」→ 可列出全页标题当目录
页脚「分组……版权信息」「内容信息,地标」
结论:语义化不只是「代码洁癖」,它是读屏用户的导航地图。 写好 <header> <nav> <main> <footer> 和连续的标题层级,无障碍就完成了一大半。

三、alt:图片的「语音替身」

速读员看不见图片,它只念 <img> 的 alt 属性—— alt 就是图片的「语音替身」。写 alt 记住三原则:

  • 信息图写清内容:图片想传达什么就写什么,如「2026 上半年学习时长柱状图,6 月最高」。
  • 装饰图写空 alt:纯好看的花边、分隔线写 alt="",速读员会直接跳过,不打扰用户。
  • 别以「图片」二字开头:速读员自己会报「图像」,你再写「图片:一只猫」就成了「图像 图片 一只猫」。

alt 还有一个隐藏福利:图片加载失败时,浏览器会把 alt 文字显示在占位框里。 网速差、图床挂了的时候,用户也不至于面对一个莫名其妙的裂图图标。

三张图都指向不存在的路径,浏览器显示裂图 + alt 文字兜底:把第三张的 alt 改成你写的描述,看占位框文字跟着变;再把它改成 alt="",看它「隐身」
判断 alt 写没写好的土办法:捂住图片只看 alt 文字, 如果还能 get 到图片要表达的信息,就合格了。

四、label:表单的无障碍关键

输入框旁边的说明文字,如果只是孤零零一段文本,速读员念到输入框时只会说 「编辑框」——填什么?全靠猜。<label> 就是文字和输入框之间的 「红绳」,两种牵法:

牵上红绳的好处是双份的:速读员会先念「邮箱」再念「编辑框」; 更妙的是,点击 label 文字本身就能聚焦输入框—— 点一大块文字比点一个小框容易得多,手指粗的、手抖的、在地铁里晃的用户全都受益。

用鼠标分别点两侧的「邮箱」二字:左边牵了红绳,点文字输入框就亮;右边只是普通文字,点了毫无反应(纯 HTML 原生行为,无需任何 JS)

五、键盘导航:Tab 键走天下

很多人从头到尾只用键盘:运动障碍用户、笔记本触摸板坏了的人、追求效率的程序员。 他们的全部操作就是 Tab 前进、Shift+Tab 后退、Enter 确认。 好消息是,原生可交互元素——<a>、<button>、 <input>——天生就能被 Tab 到,不用你做任何事。

tabindex 三个取值速查:谁能进 Tab 队伍
写法效果建议
(不写)原生可交互元素自动可 Tab;div / span 不可 Tab首选:能用 <button> 就别用 div 冒充
tabindex="0"让任何元素(如 div)进入 Tab 顺序,位置按文档流万不得已才用;用了还得自己补键盘事件和焦点样式
tabindex="-1"不能 Tab 到,但可被脚本 focus()(如弹窗标题)配合 JS 做焦点管理时用
tabindex="2"(大于 0)强行插队,打乱自然顺序别用:Tab 顺序会乱成一锅粥

焦点圈(focus outline)是键盘用户的「鼠标指针」—— 它告诉用户「你现在在哪」。:focus-visible 只在键盘聚焦时显示焦点圈, 鼠标点击不显示,兼顾美观与可用。

先用鼠标点一下预览区,再反复按 Tab 键:看焦点框依次跳过链接 → 按钮 → 输入框 → 那个带 tabindex="0" 的 div;按 Shift+Tab 则倒着走
千万别为了「好看」写 outline: none 又不给替代样式—— 键盘用户会瞬间在你的页面里「失明」,不知道焦点在哪。要么留着默认焦点圈, 要么像上面实验一样换成更醒目的自定义 :focus-visible 样式。

六、aria-*:给机器的补充说明

aria-* 系列属性是专门写给辅助技术看的「补充说明」, 普通用户完全看不见。但请牢记第一原则: 能用语义标签解决,就别用 aria—— 一个原生 <button> 胜过一百行 aria 补丁。 aria 只用于语义标签覆盖不到的角落。

常用 aria 属性速查:什么时候才轮到它出场
属性作用典型场景
aria-label给元素一个文字名字,只有机器读得到纯图标按钮(一个 ✕ 没有文字):aria-label="关闭"
aria-hidden="true"对读屏隐身,就当它不存在纯装饰图标、分隔花纹,别让速读员念出「星星 星星 星星」
aria-describedby指向一段补充说明的 id密码框关联「至少 8 位,含字母数字」的提示
role告诉机器「这玩意儿是什么角色」谨慎用:多数语义标签自带 role,手抖写错比不写更糟
下面两个 ✕ 按钮看起来一模一样——这就是重点:aria 是写给机器的,眼睛永远看不出差别。读源码找出哪个对速读员友好;把第一个按钮的 aria-label 删掉,它在读屏里就只剩一声「按钮」

七、颜色对比度:别把浅灰当正文色

浅灰字配白底,设计稿上很「高级」,阳光下、老花眼里就是一片空白。 国际上用 WCAG 标准给对比度划了红线——对比度是个比值, 最黑配最白是 21:1,同色是 1:1:

WCAG AA 级对比度红线:文字至少要多「深」
文字类型最低对比度说明
正文、普通文字≥ 4.5 : 1绝大多数文字按这条执行
大字号(≥24px 或 ≥19px 加粗)≥ 3 : 1字大就自带清晰度,要求放宽
纯装饰、禁用态无要求不传信息的元素不受限

常见翻车现场:浅灰字白底(#CCC 配 #FFF,对比度约 1.6:1)、 白字浅黄底、品牌色直接当正文色。下面的实验让你亲手感受差距:

四张色卡,两好两差:把 .bad-a 的 color 改成 #8F3A26,看它瞬间清晰;再把 .good-a 改成 #C08A3E,体验「设计稿高级、阳光下抓瞎」
设计好看 ≠ 看得清。设计稿里的「高级灰」搬到真实世界—— 强光、老花、廉价屏幕——常常直接不及格。正文色下手狠一点, 拿不准就用 DevTools 的取色器(它会直接标出对比度数值和 AA/AAA 达标线)自查。

八、小结

  • a11y = accessibility(a 和 y 之间 11 个字母);无障碍受益的是所有人——路缘坡效应。
  • 屏幕阅读器是「读屏的速读员」,语义化标签就是它唯一的眼睛:地标 + 标题层级 = 可跳读的目录。
  • alt 是图片的语音替身:信息图写清内容、装饰图 alt=""、别用「图片」开头;加载失败时它还会兜底显示。
  • <label> 用 for+id 或包裹式牵上红绳:读屏能念、点文字也能聚焦输入框。
  • 原生可交互元素天生可 Tab;tabindex 只用 0 和 -1,别用大于 0 的值;焦点圈是键盘用户的鼠标指针,别随手 outline: none。
  • aria 第一原则:能用语义标签就不用 aria;常用三件套 aria-label(图标按钮命名)、aria-hidden(装饰隐身)、role(谨慎用)。
  • 正文对比度 ≥4.5:1,大字号 ≥3:1——设计好看不等于看得清。
动手练习:① 拔掉鼠标,只用 Tab / Shift+Tab / Enter 把你之前写的页面完整走一遍,看每一步焦点是否可见、顺序是否合理; ② 给页面里所有 <img> 补上合格的 alt(装饰图写空); ③ 检查所有表单控件都有关联的 <label>,点文字验证能聚焦。