dialog元素默认隐藏,必须调用show()或showModal()才显示;showModal()创建模态遮罩并锁定焦点,show()为非模态;关闭需手动close(),点击遮罩关闭须监听close事件;Safari 15.4+支持,旧版需polyfill。
show() 或 showModal()
浏览器原生 dialog 不像 div 那样默认渲染为可见元素——它初始状态是 display: none,即使写在 HTML 里也不会自动出现。不调用方法,它就只是个“隐形 DOM 节点”。
常见错误是只写 HTML 结构,没加 JS 控制:
<dialog id="myDialog"> <p>这是内容</p> <button onclick="this.closest('dialog').close()">关闭</button></dialog>
这段代码运行后,页面上什么都不会出现。必须显式触发:
document.getElementById('myDialog').show():非模态,背景可交互document.getElementById('myDialog').showModal():模态,带 backdrop、强制聚焦、Esc 可关document.createElement('dialog') 后立刻调用,需先 appendChild)close 事件,不是 click
dialog 的遮罩层(backdrop)点击行为由浏览器控制,不会触发父级或 body 的 click 事件。直接绑 onclick 到 dialog 上也无效——因为点击 backdrop 时,事件目标是伪元素 ::backdrop,不可捕获。
立即学习“前端免费学习笔记(深入)”;
正确响应方式只有监听其自身的 close 事件:
const dlg = document.getElementById('myDialog');dlg.addEventListener('close', () => { console.log('用户关闭了对话框(点 backdrop / Esc / close())');});
close()、showModal() 后按 Esc、点击 backdrop 时都会触发show() 创建的非模态 dialog 点击 backdrop 不会自动关闭,也不触发 close
click 并判断 event.target === dlg
showModal()
Safari 对 dialog 的实现长期滞后:showModal() 直到 iOS 16.4 和 macOS Ventura 13.3 才正式支持;更早版本调用会静默失败(无报错,但不显示)。而 show() 在 Safari 中始终不可用(会抛 DOMException: The element does not support showing.)。
兼容处理建议:
'showModal' in HTMLDialogElement.prototype 判断是否可用模态模式position: fixed + aria-modal="true" 的 div 模拟::backdrop 样式支持也不完整,比如 background 透明度可能异常,建议用半透黑 rgba(0,0,0,0.5) 而非 hsla
虽然 showModal() 会自动将焦点移入 dialog,但它不会限制 Tab 键循环范围——焦点仍可跳出到 dialog 外的元素,破坏模态体验。且首次打开时,若 dialog 内没有可聚焦子元素(如 button、input),焦点可能落在 body,导致键盘操作失效。
安全做法:
tabindex="-1" 或可聚焦元素,并在 showModal() 后立即 .focus()
keydown 拦截 Tab 键,手动控制焦点在 dialog 内循环document.activeElement 记录)autofocus 属性——它在 Safari 中对 dialog 无效dialog 最容易被忽略的是 Safari 兼容性边界和焦点逻辑闭环。哪怕只支持最新 Chrome/Firefox,也得考虑用户按住 Shift+Tab 从第一个控件跳出去的情况。