现代浏览器推荐直接使用 dialog 元素实现全屏遮罩,其 showModal() 自动处理层叠、滚动禁用和 backdrop 覆盖,::backdrop 天然满屏,点击默认不关闭,Esc/Tab 键盘支持开箱即用;Safari 15.4+ 才完整支持,旧版需 fallback;z-index 失效多因父级隐式层叠上下文,可提级至 body 或加 isolation: isolate;遮罩须显式设 top/left/width/height 为 0/0/100%/100%,避免 100vw/vh 兼容问题;局部遮罩需父容器 position: relative;pointer-events 和 background 透明方式影响交互逻辑,background 应用 rgba/hsla 而非 opacity。
dialog 元素在现代浏览器中已足够可靠,直接用它比手写 div + z-index 更快、更稳;旧版浏览器(如 IE11 或部分安卓 WebView)才需要降级方案。dialog 实现全屏遮罩最简路径不用算宽高、不操心 z-index 层叠上下文、不手动禁用背景滚动——showModal() 自动搞定所有模态行为。
dialog 默认创建独立层叠上下文,::backdrop 伪元素天然覆盖整个视口,无需 position: fixed 和 100vw/100vh
dialog::backdrop 的 click 事件并调用 close()
Esc 关闭、Tab 在弹窗内循环聚焦,无障碍基础比手写方案强得多showModal();若需兼容 Safari 15.3 及更早版本,得 fallback 到 show() + 手动加 inert 属性禁用背景z-index 失效时优先查层叠上下文,不是调数字遮罩层没盖住目标内容?90% 情况不是 z-index 写小了,而是父容器触发了隐式层叠上下文(比如加了 transform、opacity: 0.99、filter),导致子元素的 z-index 只在内部比较。
transform 或 opacity < 1
isolation: isolate,强制它不隔离子层叠顺序(但慎用,可能影响性能)<body> 底部,和页面主体同级,彻底避开嵌套干扰空 div 即使 position: fixed 且 z-index 很高,也可能因高度为 0 而“看不见”,尤其当它没子元素或子元素 display: none 时。
top: 0; left: 0; width: 100%; height: 100%,而不是依赖 100vw/100vh(后者在 iOS Safari 横屏时有兼容问题)position: relative,遮罩层用 position: absolute,否则会相对 <html> 定位,错位风险极高display: block 就能自动撑开——块级元素在无内容、无宽高声明时,高度就是 0新手常误设 pointer-events: none,结果遮罩形同虚设;但设成 auto 后又发现点不到底下的按钮——问题不在遮罩本身,而在事件流向设计。
立即学习“前端免费学习笔记(深入)”;
pointer-events: auto + background: rgba(0,0,0,0.5),它自然拦截所有穿透事件click 事件并 stopPropagation(),避免意外触发底层按钮document,而应监听遮罩层自身 click 并检查 event.target === dialog(即点在 backdrop 上)background 必须带 alpha 通道(如 rgba 或 hsla),用 opacity 会把整个遮罩内容(包括文字、图标)一起变透明,且触发新层叠上下文。