点击穿透取决于命中测试结果而非事件冒泡,关键在于 pointer-events 属性:设为 none 的元素被跳过,底层元素成为事件目标;z-index 仅影响绘制顺序,不决定事件接收。

事件冒泡本身不直接影响点击穿透——穿透与否,取决于哪一层真正接收了初始点击事件,而不是事件后续怎么冒泡。
点击穿透的关键在“事件捕获起点”,不是冒泡路径
浏览器点击时,先做“命中测试”(hit testing):从最顶层可见且 pointer-events: auto 的元素开始往下查,找到第一个能响应点击的元素作为事件目标。只有这个元素会触发 click,之后才进入捕获→目标→冒泡阶段。
所以,如果一个绝对定位的 .overlay 盖住了底层按钮,但没设 pointer-events: none,那它就是命中目标——事件根本不会到达按钮,冒泡再完整也无用。
pointer-events: none 才是穿透的开关
给 .overlay 加 pointer-events: none,等于告诉浏览器:“别把我当点击目标”,于是命中测试自动跳过它,继续往下找,直到碰到按钮——此时按钮才是事件目标,冒泡照常发生(比如从按钮冒泡到 body)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 错误做法:只靠
e.stopPropagation()挡冒泡——这解决不了“点不到按钮”的问题,因为按钮压根没收到事件 - 正确顺序:先让 overlay 不拦截(
pointer-events: none),再让按钮自然成为目标,冒泡行为无需干预
冒泡可能干扰的其实是“误触”场景
当 overlay 部分区域需要交互(比如关闭按钮),而其余区域要穿透时,容易出问题:
- 若关闭按钮和 overlay 在同一 DOM 树中(如
<div class="overlay"><button class="close"></button></div>),且 overlay 设了pointer-events: none,按钮必须显式设pointer-events: auto - 否则按钮虽在视觉上可见,但因继承了父级的
none,依然无法成为命中目标——冒泡无从谈起 - 更稳妥的做法是把按钮抽成 overlay 的兄弟节点,避免继承干扰
z-index 和层叠上下文不决定事件流向
z-index 只控制谁“画在上面”,不影响事件是否被接收。即使 overlay 的 z-index 是 9999,只要它设了 pointer-events: none,点击就直接穿透;反之,哪怕 z-index 是 1,只要没设 none,它照样拦住所有点击。
真正要注意的是层叠上下文是否割裂了视觉层级——比如父容器用了 transform,可能导致 overlay 和按钮不在同一比较平面,这时 z-index 失效,但 pointer-events 仍按 DOM 结构和样式独立生效。

















