全屏遮罩必须用 position: fixed,局部遮罩才用 position: absolute 且父容器需设非 static 定位;z-index 失效主因是层叠上下文隔离;遮罩需显式设置宽高;点击关闭需阻止事件冒泡;移动端需禁用滚动穿透。

遮罩层用 position: fixed 还是 position: absolute
全屏遮罩必须用 position: fixed,否则滚动时会跟着内容移位,露出底下页面。局部遮罩(比如只盖一个卡片)才用 position: absolute,但它的父容器必须设 position: relative 或其他非 static 值,否则定位基准会跳到 ,导致错位。
常见错误:直接写 .overlay { position: absolute; } 却没管父级,结果遮罩飘到左上角;或者误用 position: static,这时 z-index 完全无效。
z-index 失效的真正原因不是数值太小
90% 的 z-index 不生效,是因为遮罩层和目标内容不在同一个层叠上下文里。比如它们的共同父容器加了 transform、opacity: 0.99 或 filter,就会隐式创建新层叠上下文,子元素的 z-index 只在内部比较,压不过外部元素。
排查方法:用浏览器开发者工具打开 “Computed” 面板,看遮罩层和被遮盖元素的最近共同祖先是否带 transform 或 opacity 。
- 临时解法:给那个“意外触发上下文”的父元素加
isolation: isolate - 长期解法:把遮罩层 DOM 节点提级到
底部,和页面主体同级 - 别靠调大
z-index硬扛——设成 99999 也没用,上下文隔离了就隔绝了比较
遮罩层尺寸必须显式撑开,不能靠内容或默认值
空的 <div class="overlay"></div> 即使 position: fixed 且 z-index 很高,也可能高度为 0,看起来像没生效。安全写法统一用:
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
}
不用 100vw/100vh 是因为 iOS Safari 横屏时有兼容问题;也不依赖 html, body { height: 100% },避免继承链断裂。
如果遮罩只盖局部(如某个卡片),则父容器需设 position: relative,遮罩层用 position: absolute 并配 top: 0; right: 0; bottom: 0; left: 0;。
点击遮罩关闭弹窗时,为什么点到弹窗内部也关了
这是事件冒泡导致的——遮罩层监听了 click,但用户实际点的是弹窗内容区的透明区域(比如 padding 区),事件从内向外冒泡,最终触发遮罩的 handler。
正确做法是监听遮罩层自身,并确保只响应它本体的点击:
- 给遮罩层绑定
click,回调里判断event.target === event.currentTarget - 更稳妥:给弹窗内容区容器加一层
position: relative,并在其click事件中调用e.stopPropagation() - 别在 HTML 里写
onclick="closeModal()",尤其在 React/Vue 中会破坏状态同步
移动端还要额外处理滚动穿透:iOS Safari 不会自动禁用 滚动,得用 JS 记录 window.scrollY,临时设 body { position: fixed; top: -${scrollY}px; },关闭时恢复。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











