dialog、modal 与返回焦点
模态对话框打开后,键盘用户必须知道焦点在哪里、如何关闭,以及关闭后回到哪个控件。原生 <dialog> 能提供部分语义,但触发按钮和焦点恢复仍需要明确实现。
最小实验:保存并恢复焦点
html
<button id="open">编辑标题</button>
<dialog id="editor">
<form method="dialog">
<label>标题 <input id="title" /></label>
<button value="cancel">取消</button>
<button value="save">保存</button>
</form>
</dialog>
<script>
const open = document.querySelector('#open')
const dialog = document.querySelector('#editor')
const title = document.querySelector('#title')
let returnFocus
open.addEventListener('click', () => {
returnFocus = document.activeElement
dialog.showModal()
title.focus()
})
dialog.addEventListener('close', () => returnFocus?.focus())
</script>点击“编辑标题”,按 Tab 检查焦点是否留在对话框内;按 Escape 关闭,确认焦点回到按钮。把 dialog.showModal() 改为 dialog.show(),比较背景可交互性和键盘行为。
机制与边界
showModal() 创建模态 top layer,并使背景内容不可交互;close 事件只表示关闭完成,不会自动替你恢复业务焦点。删除触发按钮时要提供合理的后备焦点。真实项目还需用键盘任务和读屏工具验证名称、错误反馈和关闭方式。
练习
- 增加表单校验错误,把错误消息与输入关联,并让焦点落到第一个错误控件。
- 测试用户在打开后按 Escape、点击取消和提交三条路径,记录返回焦点。
- 在旧浏览器不支持
<dialog>时,说明降级到自定义模态层需要补齐哪些语义和焦点管理。