313 字
2 分钟
原生 dialog 元素:模态框的正确打开方式

上周拆掉项目里一个 300 行的手写模态框组件,换成原生 <dialog> 元素,组件文件从 300 行缩到 40 行。这东西值得单独记一篇。

为什么它更好#

手写模态框绕不开三个坑:焦点会跑到页面背后、Esc 关不掉、z-index 层层加码还是被浮层盖住。<dialog> 把三个问题全部内建解决:

  • showModal() 打开后焦点圈定在对话框内,Tab 键出不去
  • Esc 自动触发 close 事件
  • 渲染在 top layer,永远盖在普通层叠上下文之上,不用管 z-index

基本用法#

<dialog id="confirm">
<p>确认删除这条记录?</p>
<form method="dialog">
<button value="cancel">取消</button>
<button value="ok">删除</button>
</form>
</dialog>
const dlg = document.querySelector('#confirm');
dlg.showModal();
dlg.addEventListener('close', () => {
if (dlg.returnValue === 'ok') doDelete();
});

form method="dialog" 会自动关闭对话框并把按钮的 value 塞进 returnValue,连事件监听都省了。

样式#

遮罩用 ::backdrop 伪元素:

dialog::backdrop {
background: rgb(0 0 0 / 40%);
backdrop-filter: blur(2px);
}

打开时有默认的居中定位,可以用 margin: auto 微调。出场动画建议用 transition 配合 allow-discrete,比 JS 控制 class 干净得多。

唯一要注意的:show() 和 showModal() 是两种东西,前者是普通 inline 弹层,没有遮罩也不圈定焦点,别调混了。

原生 dialog 元素:模态框的正确打开方式
https://oliver6868686.tech/posts/dialog-element/
作者
Oli
发布于
2026-04-20
许可协议
CC BY-NC-SA 4.0