全屏遮罩必须用 position: fixed 并设 top/right/bottom/left 为 0,禁用 absolute;背景用 rgba() 而非 opacity;z-index 至少 1060 且避免祖先触发层叠上下文;点击关闭需判断 e.target === e.currenttarget;滚动锁定需记录并重置 body scrolltop。

全屏遮罩必须用 position: fixed,不是 absolute
用 position: absolute 写遮罩,十次有九次会漏底、错位或被父容器裁剪——尤其当祖先元素设了 overflow: hidden 或 transform 时,遮罩直接“消失”。position: fixed 才能真正锚定视口四角,滚动也不偏移。
关键写法是:top: 0; right: 0; bottom: 0; left: 0,而不是 width: 100vw; height: 100vh。后者在 iOS Safari 中受地址栏缩放影响,vh 值会跳变,导致底部留白或溢出。
移动端更稳的兜底方案:
- 优先用
document.documentElement.clientHeight动态设高度(避免window.innerHeight被 WebView 容器干扰) - 不依赖 JS 时,可用
min-height: 100dvh(Chrome 105+/Safari 16.4+ 支持),比100vh更准
背景必须用 rgba(),别碰 opacity
opacity: 0.5 是陷阱:它会让整个遮罩层及其所有子元素(比如弹窗、按钮、文字)一起变透明,内容立刻糊成一片。而 background-color: rgba(0, 0, 0, 0.5) 只作用于背景色本身,弹窗保持清晰可读。
alpha 值建议选 0.4–0.6:
-
0.3太浅,压不住底层内容 -
0.7太深,文字对比度不足,尤其配灰色 UI 时容易看不清 - 若需视觉层次感,加
backdrop-filter: blur(2px)(注意 Chrome 99+/Safari 支持,Firefox 需前缀)
z-index 不够高,遮罩就被盖住
Bootstrap 默认 .modal-backdrop 的 z-index 是 1040,.modal 是 1050。你的遮罩层至少得设 z-index: 1060,否则会被 modal 内容穿透,甚至被第三方组件(如 Ant Design 的 Tooltip)盖住。
但光设高值还不够:
- 避免在遮罩父容器上用
transform、filter或will-change—— 这些会创建新层叠上下文,让子元素的z-index失效 - 检查是否意外触发了 stacking context 分裂,比如某个祖先 div 用了
opacity: 0.99 - 真不确定层级时,用浏览器开发者工具的 “Layers” 面板直接看渲染层顺序
点击遮罩关闭弹窗,但别误关弹窗内容
监听遮罩 click 事件后直接调 closeModal(),会导致点弹窗任意位置都关闭——因为事件从子元素冒泡上来。最安全的做法是判断点击目标是否为遮罩本体:
overlay.addEventListener('click', e => { if (e.target === e.currentTarget) closeModal(); });
如果弹窗内有可聚焦元素(如 <input>),还得额外处理:
- 给弹窗容器加
pointer-events: auto(默认已是,但显式声明更稳妥) - 所有内部交互元素加
scroll-margin: 0,防止focus()触发scrollIntoView导致页面跳动 - 遮罩显示时记录
body.scrollTop,并用body.style.position = 'fixed'+body.style.top = -scrollTop + 'px'锁定位置,避免关闭后页面回弹
.modal-backdrop 就能搞定的事,它涉及定位机制、层叠上下文、移动端滚动行为、事件冒泡控制等多个耦合点。最容易被忽略的是:遮罩层和弹窗必须是两个独立 DOM 节点,且遮罩的 pointer-events 和弹窗的 z-index 必须分层控制,否则任何一处松动都会导致交互失效。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











