浏览器未触发:hover是因为底层元素被遮挡而未参与hit-test,根本原因在于层叠上下文导致z-index失效或pointer-events阻断,需通过DevTools定位遮挡源并检查祖先节点的opacity/transform等属性。

不是“不能触发”,而是根本没收到鼠标事件——浏览器把悬停判定落在了上层元素上,底层元素压根没被 hit-test 到。
z-index低 ≠ hover失效,而是元素被遮挡
很多人误以为 z-index 低会导致 :hover “不生效”,其实它根本没机会生效。浏览器的事件分发(hit-testing)是按渲染层从上到下逐层检测的,一旦鼠标坐标落在某个可交互、且 pointer-events: auto 的上层元素上,事件就终止了,不会穿透到底层。
- 用 Chrome DevTools 的
Elements面板按Ctrl+Shift+C悬停目标区域,看高亮框是否准确套在你要 hover 的元素上 - 若高亮的是别的 DOM 节点(比如广告遮罩、伪元素、空 div),说明它被盖住了
-
z-index只影响绘制顺序,不改变事件捕获路径;遮挡源未必是z-index高的兄弟,更可能是父级意外创建的层叠上下文
父容器 opacity & transform 是隐形遮挡元凶
哪怕你给目标元素设了 z-index: 9999,只要它的任意祖先节点设置了以下任一属性,就会创建新的层叠上下文,把子元素“关”在里面——此时它的 z-index 只跟同级兄弟比,无法越级对抗外层其他容器:
-
opacity: 0.99(即可触发) -
transform: translateZ(0)或任何非none的transform -
filter: blur(1px)、will-change: transform、isolation: isolate
这类属性常被用于动画优化或视觉效果,但会悄无声息地切断层级连通性。检查 Computed 面板里祖先节点是否有 stacking context 标记,就能快速定位。
立即学习“前端免费学习笔记(深入)”;
pointer-events: none 是精确拦截开关
当遮罩层(如半透明蒙版、加载 overlay)必须存在又不能阻断下层交互时,pointer-events: none 是唯一可控手段:
- 给遮罩层加
pointer-events: none,鼠标事件会直接透过去 - 但注意:该属性对整个元素生效,包括其所有子元素;如果遮罩内有按钮需点击,得单独给按钮设
pointer-events: auto - 不要滥用
pointer-events: all(它不是标准值,无效)
伪元素错位常因 position 缺失
写 .box:hover::after 却发现图标飘到奇怪位置?大概率是伪元素没设 position:
-
::before/::after默认是position: static,不参与定位流,z-index和top/right全部失效 - 必须显式声明
position: absolute(或relative),并确保父元素有position: relative作为定位参考 - 避免在父级用
opacity: 0.99,否则伪元素的z-index会被锁死在局部上下文中
真正难排查的从来不是 z-index 数值大小,而是层叠上下文的嵌套边界——它像一层层透明玻璃,每一块都重新定义了“谁在上面”的规则。动手前先打开 Layers 面板或勾选 Paint flashing,比盲目调 z-index 有效十倍。


















