关闭modal时Screen Reader播报提示的实现方案咨询
Modal关闭场景的读屏适配实现方案
核心要拆成焦点正确回迁、关闭状态播报两个部分做,两者必须匹配,不能出现播报的焦点位置和实际焦点位置不一致的问题,具体落地方式如下:
- 先做对焦点回迁逻辑,这是整个功能的基础
弹窗触发打开的瞬间,立刻存下当时触发弹窗的DOM元素引用(比如点击的“新建”按钮、“查看详情”按钮)。当用户点击X、Cancel按钮触发关闭时,等弹窗的DOM完全从渲染树移除/加上hidden属性隐藏后,把document.activeElement切回之前存的触发源元素。
如果触发弹窗的源元素在弹窗打开期间被移除、禁用了,就把焦点切到最近的合理可交互落点,或者提前给页面主内容容器加tabindex="-1",把焦点落到主内容区起始位置,绝对不能关完弹窗焦点丢到body上,那样读屏会从头开始读页面,体验极差。 - 用ARIA live region做关闭状态播报,不要乱改业务元素的ARIA属性
- 提前在页面全局(比如布局组件的最外层)放一个专门给读屏用的状态播报容器,用标准的视觉隐藏样式让它不在页面上显示,但能被读屏识别,容器属性固定为
role="status" aria-live="polite" aria-atomic="true",不要用display: none、visibility: hidden隐藏它,否则读屏抓不到内容更新。
对应的视觉隐藏样式可以直接用通用方案:
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }- 等焦点成功移动到目标位置后,再往这个live region容器里写入提示文本,文本内容严格匹配实际焦点位置:比如焦点回到了打开弹窗的“编辑用户”按钮,就写“弹窗已关闭,当前焦点返回至编辑用户按钮”;如果焦点落到了主内容区,就写“弹窗已关闭,当前焦点定位至页面主内容区”。
- 写入文本后等2-3秒,清空live region的内容,避免后续切焦点的时候读屏重复读取这段提示。
- 提前在页面全局(比如布局组件的最外层)放一个专门给读屏用的状态播报容器,用标准的视觉隐藏样式让它不在页面上显示,但能被读屏识别,容器属性固定为
- 几个必须避开的坑
- 不要给X、Cancel按钮加超长的
aria-label,把关闭后的焦点提示写到按钮的描述里——那是操作前的提示,用户点完按钮要的是操作结果反馈,混在一起会造成信息冗余。 - 不要用
role="alert"或者aria-live="assertive"做这个提示,这个优先级会直接打断读屏当前的朗读内容,属于强打断级提示,普通操作反馈用polite级别就足够。 - 不要在焦点回迁的目标元素上绑
aria-describedby指向提示文本,否则用户后续再操作这个元素(比如按回车、切焦点再切回来)的时候,读屏会反复读这段关闭提示,干扰正常操作。 - 不要只测单款读屏:至少要覆盖Windows端NVDA+Chrome、JAWS+Edge,macOS端VoiceOver+Safari三个组合,不同读屏的默认朗读逻辑有差异——比如NVDA在焦点移动后会自动朗读焦点元素的名称,这时候live region里只需要写“弹窗已关闭”就行,不用重复读焦点位置,避免信息重复。
- 不要给X、Cancel按钮加超长的
- 如果你用的是第三方UI组件库,先检查组件默认行为
目前主流的无障碍优先组件库默认已经实现了打开弹窗存触发源、关闭回移焦点的逻辑,不需要自己重复写焦点处理代码,只需要补对应的live region提示逻辑即可,重复绑定焦点事件反而可能造成焦点跳动、重复播报的问题。
内容的提问来源于stack exchange,提问作者Prerit
相关产品推荐
相关产品推荐

