只有当弹窗具备模态交互特征时才适用role="dialog",需配套aria-labelledby和aria-modal="true",并手动实现焦点管理;原生<dialog>因兼容性问题在旧版Safari中受限。

role="dialog" 什么时候该用
只有当弹窗具备「模态交互」特征时才适用:role="dialog"。它不是给所有浮层加的装饰属性,而是告诉辅助技术:“这是一个需要用户响应、会阻断背景内容操作的临时界面”。比如登录框、确认删除弹窗、表单提交反馈——它们有明确的焦点管理需求、必须按 Esc 关闭、背景应被 aria-modal="true" 隔离。纯展示型 tooltip、下拉菜单、侧边栏都不该用。
必须配套的 aria 属性有哪些
单独写 role="dialog" 几乎没用,屏幕阅读器会忽略或误读。关键配套项只有两个,缺一不可:
-
aria-labelledby指向弹窗标题元素的id(不能是空字符串或不存在的 ID) -
aria-modal="true"告诉辅助技术背景内容已不可访问(注意:IE 不支持,但现代浏览器都 OK)
示例:
<div role="dialog" aria-labelledby="dialog-title" aria-modal="true"> <h2 id="dialog-title">确认删除?</h2> <p>此操作不可撤销</p> <button>取消</button> <button>确定</button> </div>
焦点管理不处理,role="dialog" 就等于没设
辅助技术依赖焦点在弹窗内循环,否则键盘用户可能跳到背景按钮上。你得手动控制:
立即学习“前端免费学习笔记(深入)”;
- 打开弹窗时,用
element.focus()把焦点移到第一个可交互元素(如第一个button或input) - 监听
Tab键,在弹窗内做焦点循环(tabindex="-1"+focus()) - 按
Esc关闭时,必须把焦点移回触发弹窗的元素(存个triggerEl引用)
漏掉任意一条,role="dialog" 的语义就失效了——它只声明意图,不自动实现行为。
为什么不用 <dialog> 元素代替
原生 <dialog> 确实自带 role="dialog"、焦点锁定和 showModal(),但兼容性差:<dialog> 在 Safari 15.4 之前不支持 aria-modal,iOS Safari 直到 16.4 才完整支持。如果你要支持 iOS 15 或旧版桌面 Safari,仍得用 div[role="dialog"] + 手动逻辑。另外,<dialog> 默认用 display: none 隐藏,动画过渡难控制,很多 UI 库(如 Bootstrap、Headless UI)也仍基于 role="dialog" 实现。



















