弹层焦点锁定
将以下提示词粘贴到你的 AI 对话框中:
请根据 https://skillhub.cn/install/skillhub.md,安装 @user_f1b049da/rfnq20260794。
技能介绍
为什么需要焦点锁定
当页面弹出自定义 Modal 或 Drawer 时,Tab 键的焦点可能跑到遮罩层后面——用户按下键盘却看不到任何元素在响应。这不是小问题:焦点丢失会导致键盘用户和屏幕阅读器用户完全无法操作弹层里的表单、按钮或链接,也破坏了 WAI-ARIA 的对话框模式。
很多人在组件库里直接用现成的 el-dialog,但项目里总有那么几个需要自己画的弹层:视觉要定制、交互要个性化,或者干脆不依赖任何 UI 框架。这时候焦点管理就全得自己兜底。
技能做了什么
核心思路很直接:用 focus-trap 把焦点圈在弹层内部。弹层根节点上调用 createFocusTrap 拿到一个实例,弹层打开时 activate(),关闭或卸载时 deactivate(),保证焦点在弹层内循环,Esc 键的关闭回调也可以配置。
推荐的实现步骤如下:
- 安装
focus-trap - 弹层显示时(
v-if为true)调用activate() - 弹层关闭时立即
deactivate(),包括组件卸载的场景 - 自测两件事:
Tab是否在弹层内循环;Esc是否能正常关闭
弹层内部至少需要有一个可聚焦元素,否则 focus-trap 无法正常工作——这一点在实现时就要留意,不要等打开弹层后才发现里面空空如也。
注意边界
这个技能解决的是焦点圈定问题,不是完整的无障碍方案。它不会帮你做色彩对比度检测、语义角色标注或屏幕阅读器兼容性扫描。项目如果要过无障碍审计,还需要配合其他工具或人工测试。
另外有两个常见的坑:一是弹层激活后忘了 deactivate(),导致页面焦点卡死在弹层里,用户连 Tab 都出不去;二是空弹层没有按钮就直接 activate(),焦点找不到落脚点反而更容易出问题。实现时请务必处理这两个场景。
使用场景
- 用 Vue 自研确认弹窗,需要 Tab 键在弹层内循环,避免焦点跑到遮罩后面导致键盘用户无法操作
- 项目不用组件库自带 Modal,需要给自定义 Drawer 补上焦点锁定和 Esc 关闭的能力
- 做一个键盘可达的 Demo 对话框,需要验证 Tab 循环和 Esc 回调是否按预期工作
- 修复线上反馈:弹层关闭后焦点没有回到触发按钮,需要在卸载时正确调用 deactivate
适合人员
- 自研无障碍弹层的前端工程师,需要一套可直接落地的焦点锁定实现方案
- 维护表单组件库的开发者,要在自定义 Drawer 里补齐键盘导航和焦点循环
- 关注 a11y 合规的技术负责人,想确认自研 Modal 的键盘交互是否达标