弹窗打开后按 Tab 键,焦点会跑到遮罩后面的链接上,一路按下去甚至能点到被盖住的按钮,弹窗里那个关闭按钮反而怎么都到不了。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,焦点没有被限制在弹窗容器里,在文档顺序上它只是一个普通节点,浏览器照 DOM 顺序派发焦点,遮罩后面的内容自然还排在队列里,所以按 Tab 就漏出去了。
「弹窗焦点锁定」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。
<button aria-expanded='false'
aria-controls='dlg'>打开</button>
<div id='dlg' role='dialog' aria-modal='true'>
<script>document.getElementById('dlg').focus()</script>
具体做法是,打开弹窗时把焦点主动移到容器里第一个可操作元素上;给容器加上 tabindex 属性,在 keydown 里截住 Tab 键的首尾循环,让焦点绕回容器;关闭弹窗后把焦点还回原来那个触发按钮,别让它掉回页面顶部。
最后用这个标准收尾,按 Tab 只在弹窗内循环,Esc 关闭后焦点落在原来那个触发按钮上,页面不会跟着滚。
