键盘用户按 Tab 在「返回 → 付款 → 取消」间移动,焦点环清晰落在当前按钮上;Enter/Space 激活后反馈出现在按钮旁。鼠标悬停换色作为附加反馈,不替代焦点环。
先用实验台测键盘当前位置
一条「确认订单」操作:模拟 Tab 在三个按钮间移动,焦点环落在当前按钮上。切到「移除焦点环」的错误示范,看键盘用户为什么会迷路。
焦点可见性实验台
一条「确认订单」操作:返回 / 付款 / 取消,按任务顺序进入 Tab。模拟 Tab 移动焦点,看焦点环落在哪个按钮上; 切到「移除焦点环」的错误示范再 Tab 一次——键盘用户立刻找不到自己。
确认订单
Tab 顺序 = 任务顺序(返回 → 付款 → 取消)。焦点环用足够厚度与偏移,圆角胶囊也能看清。
按「模拟 Tab / Shift+Tab」在三个按钮间移动,焦点环跟着落到当前按钮上。按「模拟激活」看激活反馈,或按「模拟悬停当前」对比——hover 换色跟随指针,不跟随 Tab。
从刚才的操作里提炼
你在实验台上看到的就是焦点的核心工作方式。
- 焦点 = 键盘当前位置:焦点环不是装饰,是键盘用户的"光标"。实验台里焦点环跟着 Tab 落到当前按钮上,告诉你停在了哪。
- Tab 顺序 = 任务/阅读顺序:返回 → 付款 → 取消按任务顺序进入 Tab;DOM 顺序和视觉顺序一致,不要用正整数 tabindex 打乱。
- 环要可见、不被吞掉:足够厚度(≥2px)和偏移(offset),圆角、阴影或父级 overflow 裁切后仍能看清——切到错误示范移除环,键盘立刻迷路。
- 激活有反馈:Enter/Space 激活后,反馈落在当前按钮上(实验台里出现「已激活」),键盘用户知道刚才操作的是哪个控件。
- hover ≠ focus,不能互相替代:悬停换色跟随鼠标指针,焦点环跟随键盘 Tab。实验台里「模拟悬停」换的是指针所在按钮的颜色,不是键盘位置。
- 弹层与菜单的焦点规则:弹层打开焦点进入并限制在窗内(focus trap),关闭后焦点返回触发按钮;菜单打开后首选项可进入。
什么时候关注焦点
从用户信号判断,也要知道什么时候它单独不够。
- 关注:所有可交互控件(按钮、链接、输入、自定义组件)都需要键盘可达和可见焦点环。
- 关注:键盘走查时焦点顺序是否符合任务顺序、焦点是否被吞掉或跳到不可见元素。
- 不替代:悬停反馈——hover 是鼠标路径的附加提示,不能顶替键盘焦点环。
- 不替代:屏幕阅读器焦点(无障碍树)——视觉焦点环服务键盘用户,AT 另有读取路径,两者要同时支持。
怎么用:从触发到可见的最短路径
让键盘用户始终看得见当前位置,并能在控件上完成操作。
- 用
:focus-visible给所有真实交互控件焦点环(厚度 ≥2px、offset ≥2px),鼠标点击时不显环、键盘 Tab 时显环。 - 保持 DOM 顺序 = 任务顺序;移除
tabindex正整数,仅在需要跳过或自定义组件时用tabindex="0"。 - 弹层打开用 focus trap 把焦点限制在窗内,关闭时
trigger.focus()把焦点还给触发按钮。 - 永远不要
outline: none后不补样式;若要去掉默认轮廓,必须换成等价或更醒目的自定义焦点环。
正反例:同一确认条,只改一处实现
围绕同一组操作按钮,只改变焦点环的处理,看键盘用户后果如何不同。
鼠标移过能看见换色,但键盘用户按 Tab 时所有按钮都没有位置标识,不知道停在哪、下一步会激活哪个。把唯一的"当前位置"藏进了指针设备才触发的伪类。
快速自测
付款页删掉焦点环、改成只在 button:hover 时变色,键盘用户按 Tab 切换按钮时会出现什么?
继续查证
术语的技术定义和行为以这些一手或权威资料为准。
下一步学
和本知识点经常一起出现的概念。