推荐使用 dialog 元素实现原生弹窗,语义清晰、自带模态行为与焦点管理;需用 showModal() 触发,确保其为 body 直接子元素以启用 backdrop,Safari 15.4+ 完整支持,旧版需补 dialog::backdrop 样式。
dialog 元素实现原生弹窗(推荐)现代浏览器已普遍支持 dialog,它语义清晰、自带模态行为和焦点管理,无需额外 JS 控制遮罩层或 Esc 关闭逻辑。
showModal() 方法触发显示,直接设 open 属性不会激活模态特性 dialog 是 body 直接子元素,否则 backdrop 可能不渲染 close() 触发 close 事件,可监听做清理;cancel 事件对应 Esc 或点击 backdrop dialog::backdrop 样式补全遮罩 <dialog id="myDialog"> <p>这是弹窗内容</p> <button onclick="this.closest('dialog').close()">确定</button></dialog><p><button onclick="document.getElementById('myDialog').showModal()">打开弹窗</button>
当需要支持 IE 或老版本 Safari 时,得手动控制显示/隐藏、遮罩、焦点锁、Esc 响应。
position: fixed + z-index 高于主内容,且宽高设为 100vh/100vw position: fixed 居中,避免受父容器 transform 或 overflow 影响偏移 focus() 聚焦到弹窗内第一个可交互元素,并拦截 Tab 键循环在弹窗内 keydown,但注意不要干扰输入框内的正常 Esc 行为(比如搜索框清空) 示例关键逻辑:
立即学习“前端免费学习笔记(深入)”;
function openModal() { document.getElementById('overlay').style.display = 'block'; const modal = document.getElementById('customModal'); modal.style.display = 'block'; modal.querySelector('button, input')?.focus();}
用户打开弹窗后滚动页面,常导致背景内容位移,体验割裂。单纯给 body 加 overflow: hidden 会同时禁掉弹窗内长内容滚动。
body 的 scrollTop,然后设 body { position: fixed; top: -scrollTop } position: static 并重置 scrollTop overflow: hidden,再给弹窗容器设 overflow-y: auto 和固定最大高度 position: fixed 的兼容问题,有时需加 touch-action: none 防止拖拽穿透 alert() / confirm()
这些是阻塞式原生对话框,会冻结整个页面 JS 执行,无法自定义样式、内容结构或动画,且在多数现代框架中已被视为反模式。
alert() 无取消路径,无法与 React/Vue 的状态流集成 confirm() 的按钮文案不可控,中文环境可能显示英文 Blocked opening 'about:blank'... 错误 aria-modal="true"、aria-labelledby),原生函数完全不支持 弹窗真正的难点不在“显示”,而在焦点管理、滚动锁定、键盘导航闭环和屏幕阅读器兼容——这些细节漏掉一个,用户就会卡住或感知不到弹窗存在。