最快解法是给遮挡层加 pointer-events: none,前提是它纯属视觉装饰;z-index 失效常因祖先元素创建了新层叠上下文,需逐级检查并临时移除 transform、opacity 等触发属性。

直接给遮挡层加 pointer-events: none,前提是它纯属视觉装饰、不需要任何交互。这是最快、最轻量、最确定的解法,不改布局、不触发重排、不影响动画或焦点逻辑。
为什么 z-index 调了也没用
z-index 不是全局排序器,只在同一个层叠上下文内生效。一个 transform: translateY(0)、opacity: 0.99、filter: blur(1px) 或 will-change: transform 就会让父元素创建新层叠上下文,子元素的 z-index 就锁死在内部,根本比不到你预期的位置。
检查方式:
- 打开开发者工具 → “Computed” 面板 → 搜索
z-index,如果显示为auto或 “not applicable”,说明已失效 - 逐级往上查祖先,找到第一个标有 “This element establishes a stacking context” 的节点
- 临时删掉它的
transform、opacity等属性,看点击是否恢复
pointer-events: none 必须加在遮挡元素自身上
这个属性不继承、不传播、不跨层生效,只对声明它的那个 DOM 节点起作用。常见错误是加在父容器上,结果遮挡子元素(比如 .mask)依然吃点击。
正确写法示例:
.mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.4);
pointer-events: none; /* ✅ 加在这里 */
}
如果遮挡层里有关闭按钮,不能靠继承恢复——父层设了 none,子树整个被跳过。必须:
- 把按钮提到同级:
,再用z-index控制视觉位置 - 或给伪元素单独设:
.mask::before { pointer-events: none; } - React/Vue 中优先用 Portal 渲染到
下
伪元素和透明层也得手动关事件
::before 和 ::after 默认参与事件流,哪怕只是画个阴影、边框或渐变,也会稳稳盖住下层链接。别指望 z-index: -1 解决——在已有层叠上下文的父容器里,它完全无效。
必须显式控制:
.overlay::before { pointer-events: none; }-
opacity: 0或visibility: hidden时,同样要配pointer-events: none;否则它们照常拦截点击 - 移动端真机测试必做:iOS Safari 对多层
pointer-events: none的穿透顺序按渲染树而非 DOM 顺序,点一下确认下层是否真响应
最容易被忽略的是层叠上下文干扰和伪元素默认参与事件流——这两点不排查清楚,光调 z-index 或反复改 pointer-events 都是白忙。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











