想象你深夜走进一栋完全没开灯的大楼,手里只有一支手电筒。你的视野只有光斑那么大,每走一步都得靠墙边的盲道引导,靠按钮上的盲文分辨方向,靠门框的塑料边条确认出口。如果你能顺利走到目的地,这栋楼对你就称得上「友好」。而这就是键盘导航要做的事:当用户看不见屏幕、手抖无法精准点按、或者根本不用鼠标时,网页必须像这栋楼一样,给出一条清晰、安全、可预测的「键盘盲道」。焦点是手电筒光斑,Tab 键是盲道,ARIA 标注是墙上的盲文,跳过导航是直达电梯,AI 辅助增强则是楼里巡逻的智能机器人。这篇文章,就是带你把整栋「无障碍大楼」从地基到智能系统完整走一遍。
无障碍与键盘导航是 AI 产品走向真实用户的第一道门槛。掌握它,你能让模型能力真正触达视障、运动障碍等群体,也能在设计评测、可访问性测试与合规审查岗位上建立不可替代的专业壁垒。
可视化演示
通过三步演示展示无障碍键盘导航核心:Tab焦点链顺序、快捷键交互效率、辅助技术兼容性测试,交互切换查看各环节设计要点。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Tab焦点链设计 Tab顺序遵循从上到下从左到右 焦点指示器必须清晰可见 WCAG 2.1 \u00a72.1 所有功能均可通过键盘操作完成。
无障碍基础
盖一栋楼之前,建筑师不会先想着装电梯,而是会先画一条无障碍坡道。很多人以为坡道只为坐轮椅的人准备,可实际上,推婴儿车的妈妈、拉行李箱的出差者、骑自行车上台阶的快递员,全都在走那条坡道。数字世界的「无障碍坡道」同理:它服务的从来不只是残障人群,而是每一个处于「临时障碍状态」的普通人——比如一只手抱着孩子、眼睛盯着屏幕但没法用鼠标、或者正在嘈杂的地铁里只能靠键盘操作。
在交互设计里,无障碍(Accessibility,简称 a11y)是指产品对尽可能多的人可用,无论他们的视觉、听觉、运动或认知能力如何。受众画像远比你想象的宽泛:全盲用户依赖屏幕阅读器,低视力和色弱用户依赖高对比度与放大,运动障碍用户(如帕金森患者)依赖键盘而非精细鼠标操作,认知障碍用户依赖清晰一致的结构。法律层面,WCAG(Web 内容无障碍指南)是全球公认的技术标准,其「POUR」四原则——可感知、可操作、可理解、健壮——几乎就是无障碍审计的检查清单。
那么,怎么量化「一条坡道到底好不好用」?最简单的方式,是看有多少人能成功抵达目标:
坡道修好了,受益的是所有人。无障碍基础不是产品发布前的「补丁」,而是大楼设计图上最初的那条线——它决定了之后每一层楼能不能被顺利到达。
- 成功人数(N_success)在一次键盘可用性测试中,能独立完成「从首页到结算」这一任务的无障碍用户人数。
- 参与总人数(N_total)参与同一测试的全部目标用户数量,包含中途放弃的人。
- 可用率(R)两者相除,得到当前设计的无障碍达成率,用于横向对比改造前后的效果。
键盘交互原理
健忘症患者半夜走进大楼,手电筒光束落在哪,他才知道自己站在哪。键盘导航世界的「手电筒光束」叫焦点(focus),它标记了当前页面「正在与用户对话」的那个元素:是个链接?是个按钮?还是个输入框?用户按下 Tab 键,手电筒就从当前元素移动到下一个可交互元素;按下 Shift+Tab,它又沿着原路退回。这个移动路径,就是键盘用户唯一的「盲道」。
盲道不能乱铺。浏览器默认按文档在 HTML 中的书写顺序(即 DOM 顺序)决定 Tab 的移动方向:先出现的元素在前面,后出现的在后面。这听起来简单,却正是许多产品的翻车点——用 CSS 的 flex 或 grid 把视觉位置重新排列后,屏幕上「右上角」的按钮,其 DOM 位置可能还在「左下角」之后,键盘用户的光斑就会像坐过山车一样在页面上乱跳。
要精心管理这条盲道,核心工具有三件:一是尽量使用原生按钮、链接、输入框,它们天然可聚焦,这叫语义化标签;二是谨慎使用 tabindex 属性,它有「三档位」——tabindex="0" 表示元素加入自然 Tab 顺序,tabindex="-1" 表示可以程序化聚焦但不进 Tab 顺序,正数值则会把元素强行提到前面(除非万不得已不要用,它会让盲道变得混乱);三是在组件挂载、卸载时主动调用 .focus() 方法,像领航员一样把光束送到正确位置。
键盘盲道的效率可以量化。假如我们记录每位用户从起点组件到达目标组件所需的 Tab 次数,就能算出平均「键盘路程」:
盲道是一条连续的、可预测的路。只要 DOM 顺序清晰、焦点管理得当,深夜访客的手电筒就能稳稳地从门口照到每一个房间,而不是在走廊里来回打转。
- 单次路程(d_i)某个用户从起点元素按 Tab 走到目标元素所经历的按键次数,比如从「搜索框」到「登录按钮」按了 3 次。
- 求和算子(Σ)把 n 个用户的单次路程全部累加,得到总键盘路程。
- 求平均(1/n × …)总路程除以用户数,得到平均里程 D_avg,用于对比不同页面结构的横向效率。
导航模式设计
深夜访客站在一楼大厅,面前有几十扇门:门卫室、储物间、电梯厅、卫生间、会议室……如果每一扇门都要挨个推开门看,他天亮也到不了会客室。所以大楼设计了一条「直达通道」:门口一块盲文牌写着「跳过大厅,直达会客室」。网页里,这个设计叫跳过导航(Skip Link),它是给键盘用户和屏幕阅读器用户的第一份礼物。
具体做法是:把页面代码最顶部的第一个可见元素做成一个「跳到主内容」链接,点击后焦点直接落到 <main> 区域。这样一来,用户不用在重复的导航菜单里按 20 次 Tab,一次就直达核心内容。除跳过导航外,导航模式设计还有两个关键部件。一是热键设计:为高频操作提供快捷键,例如 Gmail 中按 c 键写邮件、按 / 键搜索;但热键必须能关闭或可重绑定,否则会和用户自己的快捷键冲突,这就像大楼里不能所有门铃都用同一个频率。二是可见焦点:当键盘用户切换焦点时,当前元素必须有一圈清晰醒目的焦点轮廓,比如 outline: 2px solid,不能仅仅依赖鼠标悬停的变色效果——手电筒的光斑看不见,盲人根本不敢移动。
WCAG 对「可见焦点」提出了具体的视觉对比要求。焦点轮廓与相邻背景的对比度必须足够高,才能被低视力用户分辨:
直达电梯、快捷键和明亮的焦点光斑,这三样东西让键盘用户在楼里不再迷路。设计者要记住:效率来自「让用户少走弯路」,而不是把每一条路都修得更宽。
- 亮度差(L₁/L₂)将焦点样式颜色与背景颜色归一化到 0~1 的亮度空间,L₁ 取较亮者,L₂ 取较暗者。
- 补偿加值(+0.05)在分子分母同时加上 0.05,防止纯黑背景下分母为零,也符合人眼感知的物理模型。
- 门槛(≥3.0)对比率大于等于 3:1 时,焦点指示器可被低视力用户清晰识别,这也是 WCAG 2.4.7 的最低要求。
ARIA规范
深夜访客摸到一扇门前,门上没有盲文,只贴着一张打印的「会议室」标签——但他摸不出这是什么类型的门,是推拉门?旋转门?还是需要刷卡的电子门?网页里的自定义组件就面临这个困境:一个用 <div> 拼出来的下拉菜单,看起来像菜单,摸起来(在代码里)却只是一块普通区域,辅助技术根本不认识它。ARIA(无障碍富互联网应用规范)就是那一张贴在门上的标准盲文标签。
ARIA 的核心是 role 属性,它给元素声明「是什么」,比如 role="dialog" 告诉屏幕阅读器这是一个对话框,role="tablist" 表示这是一组页签。配套的 aria-label 给控件命名,相当于盲文下面的那行大字说明;aria-expanded 告诉用户菜单当前是展开还是收起。有了这些标签,辅助技术才能在用户脑中重建一个完整、有语义的界面地图。
但盲文标签不能乱贴。ARIA 有一条铁律:能不用就不用。<button> 天生就是按钮,你给它加 role="button" 是画蛇添足;更危险的是贴错标签——把可点击的 <div> 明明定义了键盘行为却忘了实现方向键处理,就像门上贴了「旋转门」却是一扇推不开的死门,用户会直接撞上玻璃。ARIA 的「键盘行为」要求组件与真实控件行为对齐:弹窗要能 Esc 关闭,页签要能用左右方向键切换,滑块要能用上下键微调。此外,动态内容(比如「提交成功」的提示)需要通过 aria-live 区域告诉屏幕阅读器即时播报,否则新内容对辅助技术用户来说就像一根悄悄亮起的灯管,没有任何人通知他。
ARIA 的完整作用链可以这样描述:浏览器将原始 DOM 与 ARIA 标注合并,产出一棵专门供辅助技术消费的「无障碍树」:
盲文标签本身不会改变门的结构,它只是让访客知道门是什么、怎么开。同理,ARIA 永远不会改变视觉效果或 DOM 顺序,它只在「辅助技术的平行世界」里发挥魔力——而这份魔力,恰恰让无数自定义组件第一次变得可被理解。
- 原始结构(DOM)页面中真实的元素层级,包括
<div>、<span>等无语义标签。 - 语义标注(ARIA)开发者写入的 role、aria-* 属性,用于补充或修正语义。
- 合并映射(Map)浏览器把 DOM 结构当作骨架、ARIA 标注当作标签,合成辅助技术真正读取的无障碍树 T_acc。
屏幕阅读器
大楼欢迎深夜访客的方式,是派出一位智能向导机器人。它走在访客前头,每到一个房间就开口报出名字:「大厅」「走廊」「会议室」;访客可以喊「下一个标题」让它跳着介绍,也可以喊「去地标」直接到达指定区域。这位向导,就是屏幕阅读器(Screen Reader)。对视障用户来说,它比鼠标更本质——它不是「听网页」,而是在用户的脑海里重新搭建了整个页面的语义地图。
屏幕阅读器的阅读引擎会按无障碍树的顺序把内容线性念出来,但没人愿意从页头一个字一个字听到页脚。因此主流屏幕阅读器都有一套快捷键体系:按 H 跳到下一个标题、按 B 跳到下一个按钮、按 D 跳到下一个地标(landmark)区域、按 K 跳到下一个链接。这就像访客对向导喊口号,而不是等它逐间介绍。对开发者的启示是:页面必须提供足够多的「锚点」——清晰的标题层级、每个区域标注 role="navigation"、role="main"、role="complementary" 等地标,向导才有内容可报。
测试时说一百遍「应该没问题」都不如让向导真实走一遍。工程实践中,最常用的是 NVDA(Windows 免费)和 VoiceOver(macOS 内置)两大引擎;测试时把鼠标拔掉,全程只用键盘和读屏快捷键完成核心任务流。这条路往往能让最自信的开发瞬间清醒:原来「关闭按钮」读出来叫「第 3 个分组」,原来弹窗关闭后光标飘到了页面顶部。屏幕阅读器的读取效率可以量化——想象读屏在指定时间内能扫过多少个字符:
向导机器人的语速可以调到很快,但如果大楼里到处是没贴标签的「无名房间」,它再快也报不出有用的导航信息。给你的页面留下清晰的标题与地标,就是给向导装上能用的地图。
- 朗读字符数(N_chars)屏幕阅读器在某次交互中实际播报的文本字符总量,比如一篇新闻正文的字符数。
- 读屏耗时(T_read)从头读到尾消耗的时间秒数。
- 播报速率(V)字符数除以时间,衡量阅读器对一段内容的处理效率,也可用来比较不同读屏方案的表现。
焦点陷阱修复
大楼设计师要避免的最恐怖事故,是「密室」:访客走进一个小房间,门自动锁上,他在里面按着墙走一圈、两圈、三圈,永远绕回原地,找不到出口。网页世界里,这个密室叫焦点陷阱(Focus Trap):当用户用 Tab 键在某个区域里循环时,焦点永远逃不出去。最常见的案发现场,就是模态对话框。
模态对话框设计里有一条几乎矛盾的规则:对话框打开时,焦点必须被关在框内循环——这是防止用户把 Tab 按到背景页面去;但当对话机关闭时,焦点必须及时归还给打开它的那个按钮。如果归还逻辑缺失,用户关掉弹窗后会发现手电筒的光斑不知飘到了哪里,就像从密室逃出来却掉进了黑漆漆的管道。所以工程实践需要两件事:一是「循环托管」,即在模态框内监听 Tab 键,当焦点到达框内最后一个可聚焦元素时,按下 Tab 就把它循环回第一个元素;二是「焦点恢复」,在弹窗关闭的瞬间调用 .focus() 把焦点还给触发按钮。
要判断模态框内的焦点空间有多大,我们数一下密室里有几件「可触碰的物品」:
密室并不可怕,可怕的是没有出口和门铃。设计模态框时,先把「关闭手势」和「焦点归还」写进验收标准,再谈美观和动效——因为对键盘用户来说,能逃出来的密室才叫房间,逃不出来的叫囚笼。
- 可聚焦集合(F_modal)模态框内部所有支持键盘聚焦的元素,如按钮、链接、输入框。
- 集合大小(|…|)统计框内可聚焦元素的个数,得到循环周期 C_modal。
- 循环周期(C_modal)焦点从第一个元素绕回第一个元素所需经过的位置数量。周期越小,用户越容易在框内定位;但框内不能无限制地让 Tab 逃逸到背景。
性能优化策略
深夜访客按下电梯按钮,电梯 5 秒后才姗姗来迟;他急了,因为他看不见楼梯口在哪,也不敢摸黑走应急通道。交互系统的「电梯响应时间」,就是键盘操作后的反馈速度。无障碍不只是「能不能用」,更是「用起来顺不顺」。一项键盘操作按下后,如果页面卡顿、焦点样式延迟渲染、或者按下 Enter 半天没反应,视障用户会因为缺乏视觉反馈而严重焦虑。
性能优化有几个落点。第一是渲染性能:避免把 box-shadow、outline 等焦点样式做得太过复杂,因为焦点切换时浏览器要重新绘制;高频率的布局抖动(Layout Thrash)会让键盘用户感到「盲道在颤动」。优化方式是优先使用 transform 和 opacity 做焦点高亮动画,它们由 GPU 合成,不触发重排。第二是预加载策略:大型单页应用把可见区域内容放在第一层,把折叠区域、弹窗内容延迟到真正打开时再加载——但要注意,键盘用户比鼠标用户更容易「迷路」,预加载的分区结构必须保持焦点顺序清晰。第三是指标监控:用 PerformanceObserver 监听 longtask,用 RUM 数据追踪键盘用户从按下 Tab 到焦点样式出现的时间,这就是「焦点延迟」。
优化效果可以用前后对比来量化。假设我们测出优化前后用户完成同一键盘任务所需的时间:
电梯提速,受益的不只是深夜访客。每一个用键盘的人、每一个快速操作的效率狂魔,都会感受到那种「按下就有回应」的爽快感——性能优化永远是所有用户的共同福利。
- 优化耗时(T_before)改造前键盘用户完成「打开菜单-选第 3 项-关闭」等标准流程的平均耗时。
- 优化后耗时(T_after)同一流程在优化上线后的平均耗时。
- 优化收益(R_opt)用 1 减去耗时比,得到性能提升的百分比。该值越高,说明优化越有效。
AI辅助增强
如果这栋楼请了一位不断巡逻的智能机器人,它的任务是什么呢?它会在每晚楼里安静之后,走遍每一层,用传感器扫描盲道是否被垃圾桶堵住、盲文标签是否脱落、应急通道的灯是否亮着。它发现问题,就自动生成维修工单。在数字世界里,这位机器人就是 AI 辅助增强工具——用机器学习模型自动检测无障碍问题,甚至自动修复。
第一项能力是智能标注:传统 ARIA 标注完全依赖程序员手动写,遗漏率很高。如今可以训练模型读取页面的 DOM 结构,自动预测每个元素应有的语义角色,为 <div onclick> 补上 role="button" 和 aria-label,甚至可以生成描述性的替代文本。第二项能力是预测跳转:收集大量键盘用户的 Tab 轨迹数据后,模型可以预测「这个用户下一步大概率想聚焦哪个元素」,从而动态压缩焦点路径——好比机器人在访客伸手前就替他按好了电梯楼层。第三项能力是无障碍测试:深度学习模型结合传统规则引擎(如 axe-core),可以自动爬取页面、模拟键盘操作、识别焦点陷阱、对比度不足、缺失标签等问题,并用自然语言生成维修工单。
AI 模型的质量需要用分类指标来评估——它检测得准不准,直接决定机器人敢不敢乱贴标签:
AI 不会取代无障碍专家的判断,但它能替专家完成最枯燥的夜间巡逻。当机器人把问题清单摆到桌面,人只需要按下「一键修复」或「人工复核」——这是人机协作在无障碍领域最温柔的形态。
- 正确检出(TP + TN)模型把有问题的元素标为有问题(TP)、把没问题的元素放行(TN),这两类都是正确判断。
- 错误判断(FP + FN)误报(FP)把好元素标成问题,漏报(FN)放过了真问题,这两类都会消耗机器人或开发者的宝贵精力。
- 准确率(Acc)正确判断数除以全部判断数。准确率高,机器人贴的盲文标签才值得信任;否则它会变成一座乱贴标签的大楼。
AI 应用场景
电商大促页的无障碍智能体检
阶段:自动化测试与质量保障阶段
解决的问题:电商大促页上线时间紧、组件多,人工走查键盘导航常常漏掉深层弹窗的焦点陷阱。AI 爬虫模拟键盘用户完整走一遍「首页 → 搜索 → 商品详情 → 购物车 → 结算」流程,自动检测 Tab 顺序异常、焦点不可见、按钮无法用 Enter 激活等问题,并在 MR 合并前生成修复建议清单。
具体案例:某电商平台在大促前使用「键盘导航巡检机器人」对 120 个页面进行 AI 无障碍测试,自动发现了 34 处焦点陷阱和 57 处对比度不达标。其中最严重的是一个领券弹窗:关闭后焦点归还逻辑缺失,键盘用户会直接掉到页面底部。AI 标注出问题元素的位置和建议代码后,开发团队 2 天内完成修复,大促期无障碍客诉下降 70%。
医院挂号系统的键盘友好改造
阶段:交互设计与开发实施阶段
解决的问题:老年患者和视障用户往往不熟悉鼠标,却最需要在线挂号。传统系统把验证码做成图片、把科室选择做成鼠标悬停的下拉菜单,键盘用户根本无法操作。项目组用键盘导航设计原则重做流程,并借助 AI 辅助生成 ARIA 标注与焦点管理策略,同时加入跳过导航,让用户一键直达科室列表。
具体案例:某三甲医院互联网医院改造后,用户无需鼠标即可全程用 Tab + Enter 完成「选择科室 → 选择医生 → 填写信息 → 付费」全流程。AI 自动标注了 200 多个控件语义,并预测出患者最常访问的「复诊挂号」入口,将其加入热键直达。上线三个月,视障用户的挂号成功率从 18% 提升到 79%。
音视频平台的字幕与读屏对齐
阶段:内容生产与质量检测阶段
解决的问题:视频平台的播放器控件大量使用自定义按钮,屏幕阅读器无法识别「播放」「倍速」「字幕开关」。AI 可以自动分析播放器 DOM,识别控件位置,并生成匹配的 role、aria-label、快捷键说明,甚至用语音合成模型为视频生成高质量字幕。
具体案例:某在线教育平台为上千节课程批量生成了字幕,同时用 AI 检测播放器键盘可达性:暂停键可用空格触发、进度条可用方向键微调、字幕切换按钮有清晰的 aria-label。最终该平台获得无障碍认证,视障学生的完课率提升了一倍。
Python 演示
# -*- coding: utf-8 -*-"""键盘导航距离分析器模拟网页可聚焦元素的 Tab 顺序,对比跳过导航前后的键盘路程""" PAGE = [ "品牌 Logo", "导航:首页", "导航:产品", "导航:关于", "搜索框", "登录按钮", "文章标题 - 不可聚焦", "正文链接 A", "正文链接 B", "版权信息 - 不可聚焦", "联系邮箱链接",] class KeyboardRoute: """根据可聚焦元素顺序计算键盘用户的操作代价。""" def __init__(self, elements): # 过滤掉不可聚焦名称,得到真正的 Tab 顺序 self.focusable = [name for name in elements if "不可聚焦" not in name] def distance(self, start, end): """返回从 start 元素到 end 元素需要按 Tab 的次数。""" if start not in self.focusable or end not in self.focusable: raise ValueError("起止元素必须都可聚焦") return abs(self.focusable.index(end) - self.focusable.index(start)) def report(self, start, end): steps = self.distance(start, end) i = self.focusable.index(start) j = self.focusable.index(end) via = " -> ".join(self.focusable[i:j + 1]) return f"从「{start}」到「{end}」需按 {steps} 次 Tab\n途经: {via}" def add_skip_link(elements): """在页面最前面插入跳过导航链接。""" return ["跳过导航-直达主内容"] + elements def main(): print("=== 未加跳过链接 ===") route = KeyboardRoute(PAGE) print(route.report("品牌 Logo", "正文链接 A")) print("\n=== 添加跳过链接后 ===") new_page = add_skip_link(PAGE) new_route = KeyboardRoute(new_page) print(new_route.report("跳过导航-直达主内容", "正文链接 A")) old_steps = route.distance("品牌 Logo", "正文链接 A") new_steps = new_route.distance("跳过导航-直达主内容", "正文链接 A") print(f"\n键盘用户节省了 {old_steps - new_steps} 次 Tab 操作") if __name__ == "__main__": main()
self.focusable = [name for name in elements if "不可聚焦" not in name]这一步把「标题」「版权」等纯展示元素从 Tab 序列中过滤掉,模拟浏览器只让可交互元素获得焦点的真实行为。abs(self.focusable.index(end) - self.focusable.index(start))通过元素列表的下标差值计算 Tab 按键次数,下标差即键盘路程。def add_skip_link(elements)在页面最前面插入「跳过导航」链接,这是最常见的无障碍优化。route.report("品牌 Logo", "正文链接 A")输出从 Logo 一路 Tab 到正文链接的完整途经元素,直观展示多步操作的痛点。old_steps - new_steps计算优化前后路程差,让「一条跳过链接节省 6 次 Tab」的价值一目了然。
常见误区
误区我只要给所有元素都加上 `tabindex="0"`,键盘用户就一定能访问到它们,这样无障碍就做好了。
正解这是典型的「拆东墙补西墙」。把所有元素塞进 Tab 序列,等于把盲道铺满整栋楼,访客走一步撞一个台阶,完全失去效率。正确做法是:原生可交互元素默认保留在序列中,装饰性、展示性内容必须排除在外;tabindex="0" 只用于「本不可聚焦但确实需要交互」的自定义控件。盲道的意义是引导,而不是布满天罗地网。
为何常见:初学者容易把「无障碍」等同于「可访问」,忽略了「可操作」与「可理解」同样重要。直觉上以为元素能聚焦就等于友好,却不知道聚焦过多比聚焦不足更让人崩溃。
误区默认的 `outline` 焦点框太丑了,我把 `outline: none` 去掉,反正鼠标用户用不着它。
正解去掉 focus 样式,等于深夜大楼里拆掉了手电筒。键盘用户完全不知道当前焦点在哪,按回车可能触发任何东西。这是 WCAG 2.4.7「焦点可见」原则的直接违反。如果觉得默认轮廓难看,可以用自定义样式替代,但绝不能不提供。保留焦点样式,同时用现代 CSS 的 :focus-visible 只在键盘操作时显示,鼠标点击时不显示,美观和可用性可以兼得。
为何常见:大多数开发者在 Chrome 中用鼠标开发,根本看不见键盘焦点的问题。视觉审美焦虑压过了对真实用户群体的共情,导致最常见的无障碍事故。
误区弹窗右上角的 × 按钮能点,弹窗也能正常展示内容,键盘用户应该没问题吧?
正解问题往往出在弹窗关闭之后——焦点卡片被「归还」到哪儿去了?如果没写归还逻辑,焦点可能停留在已被销毁的 DOM 节点上,浏览器会把光束随意甩到页面顶部,用户瞬间不知道自己在哪。正确的流程是:打开时把焦点移入弹窗并循环托管,关闭时把焦点还给触发打开的那个按钮。对键盘用户来说,「回到原来位置」比「看到弹窗关闭的动画」重要得多。
为何常见:因为鼠标用户关闭弹窗后自然能看到页面整体,视觉上下文消除了「位置」困惑。而键盘用户没有全局视图,失去焦点锚点就等于在黑夜里被扔到了陌生街区。
误区做好键盘导航,就是保证所有元素都能用 Tab 键切到。屏幕阅读器用户反正也是按 Tab 听内容,只要 Tab 顺序对就行。
正解屏幕阅读器用户几乎不会用 Tab 键从头听起——他们更常用的是一套「快捷键体系」:H 跳标题、D 跳地标、K 跳链接、数字键跳对应层级的标题。Tab 只是在具体控件之间移动的细粒操作。所以真正重要的不是把所有东西塞进 Tab 序列,而是给页面布置清晰的标题层级、ARIA 地标和列表结构。把 Tab 顺序做好只是 60 分,提供语义化锚点才到 90 分。
为何常见:把「键盘导航」和「屏幕阅读器」混为一谈。键盘导航是所有键盘用户的基础,屏幕阅读器的浏览策略则更复杂,二者是交集而非等价。
误区ARIA 是万能良药。我在页面上加了一堆 `role` 和 `aria-*` 属性,无障碍评分肯定直线上升。
正解ARIA 官方文档的第一条规则就是:「不要用 ARIA,直到你能确定自己需要它。」冗余的 role 会覆盖原生语义,比如给 <button> 加 role="link" 会让屏幕阅读器把它当链接读;更危险的是,aria-hidden="true" 如果误加在拥有焦点的元素上,会让用户和辅助技术「失联」。ARIA 只能修饰语义,不能修复交互。真正可靠的方案是优先使用原生 HTML 元素。
为何常见:人们误以为无障碍问题不需要重构结构,加几个属性就能糊弄过去。ARIA 的「上手门槛低」反而害了它——随手可写,随手可错。
面试题
Q1. 键盘用户按 Tab 键切换焦点时,下一个焦点元素由什么决定?
- A.元素在文档里的 DOM 顺序← 正确答案
- B.元素绑定的视觉层级先后
- C.元素的 CSS z-index 值大小
- D.元素在屏幕上的坐标位置
答案:A。Tab 键默认按文档中 DOM 的出现顺序移动焦点,与视觉位置和 z-index 无关。这也正是为什么用 CSS 重排后容易出现焦点跳动——视觉顺序和 DOM 顺序脱节了。
Q2. tabindex="-1" 的正确作用是?
- A.将其移出默认 Tab 导航序列← 正确答案
- B.禁止该元素被鼠标点击选中
- C.让该元素获得最高的 Tab 优先级
- D.让元素自动成为页面首个焦点
答案:A。tabindex="-1" 的元素不会出现在 Tab 顺序中,但可以通过 JavaScript 调用 .focus() 让它获得焦点。这常用于「打开模态框时把焦点移入,但平时不在 Tab 序列里」的场景。
Q3. 什么是「可见焦点」(Visible Focus)?
- A.键盘操作时清晰醒目的焦点环← 正确答案
- B.鼠标悬停时变色的样式效果
- C.触屏按下后按钮的振动反馈
- D.页面加载完成时的淡入动画
答案:A。可见焦点是键盘用户定位自己位置的关键视觉指示器,通常表现为焦点轮廓(outline)。鼠标悬停样式只在有鼠标时出现,对键盘用户毫无意义。WCAG 2.4.7 要求焦点必须清晰可见,对比度不低于 3:1。
Q4. 模态对话框关闭后,焦点应当归还到哪里?
- A.触发并打开它的那个按钮上← 正确答案
- B.浏览器地址栏的输入框内
- C.页面最顶部的第一个元素
- D.对话框里的最后一个控件
答案:A。焦点归还到触发按钮,可以保持用户的任务上下文连续。如果焦点飘回页面顶部,用户就像在密室门口被突然传送回大厅,需要使用跳过导航重新定位,极大破坏操作流畅性。
Q5. 跳过导航链接(Skip Link)的正确放置位置是?
- A.页面源代码的最前面位置← 正确答案
- B.页脚版权信息的下方位置
- C.浏览器窗口的右下角位置
- D.主内容的最后一个元素处
答案:A。跳过导航必须是页面上第一个可聚焦元素,通常紧跟在 <body> 起始处,使其成为按 Tab 键的第一个落脚点。这样用户能立刻发现「跳到主内容」的出口,不必先穿过十几个导航项。
Q6. 关于 ARIA 的 role 属性,下列说法正确的有?
- A.为辅助技术提供自定义语义← 正确答案
- B.改变元素的 DOM 结构顺序
- C.让自定义组件获得可识别含义← 正确答案
- D.完全替代所有原生语义标签
答案:AC。role 的作用是给辅助技术「翻译」自定义组件的语义,让它们被识别为对话框、页签、菜单等,因此 A 和 C 正确。ARIA 永远不改变 DOM 顺序或视觉效果,B 错误;而且 ARIA 第一条规则是优先用原生标签,D 的「完全替代」错误。
Q7. 以下哪些是良好的键盘无障碍设计原则?
- A.所有交互功能都可用键盘完成← 正确答案
- B.焦点位置始终清晰可见← 正确答案
- C.完全禁止手指触控交互
- D.为重复导航提供跳出口← 正确答案
答案:ABD。键盘可操作、焦点可见、提供跳过导航是无障碍设计的三大支柱。C 的错误在于无障碍是增加可达方式,而非禁止其他方式;触控和键盘应共存,而不是互相排斥。
Q8. 屏幕阅读器用户浏览一个长页面时,最常用的方式是?
- A.标题导航等快捷跳转键← 正确答案
- B.滚轮快速滚动的浏览方式
- C.触摸屏边缘滑动翻页手势
- D.浏览器地址栏输入网址跳转
答案:A。屏幕阅读器用户通过按 H(标题)、D(地标)、K(链接)等快捷键在页面语义结构间跳跃,而不是逐行听完整个页面。这要求开发者提供清晰的标题层级和 ARIA 地标,快捷键才有可跳转的锚点。
Q9. 哪些做法可能导致焦点陷阱(Focus Trap)?
- A.缺少让用户退出取景的关闭出口← 正确答案
- B.关闭后忘记把焦点归还给触发者← 正确答案
- C.在模态框内实现焦点循环限制
- D.打开模态框后焦点滞留在背景中← 正确答案
答案:ABD。无关闭出口会让用户无法离开模态框(A),忘记归还焦点让用户在黑屏中迷失(B),焦点滞留在背景则等于没打开弹窗(D)。C 反而是正确做法——模态框内按 Tab 循环是防止焦点逃逸到背景的必要手段,关键在于循环要有出口和归还机制。
Q10. WCAG 的 POUR 原则中,「O」代表什么?
- A.Operable 可操作← 正确答案
- B.Observable 可观察
- C.Optimal 最优的
- D.Original 原创的
答案:A。POUR 对应 Perceivable(可感知)、Operable(可操作)、Understandable(可理解)、Robust(健壮)。O 是 Operable,指用户必须能够通过键盘、语音等多样化方式「操作」界面。这是个经典的基础知识陷阱题,考查是否真的读过无障碍标准原文。