点击穿透是因 visibility: hidden 或 opacity: 0 未禁用事件捕获,需用 pointer-events: none 彻底退出事件流;但设于父容器会阻断整棵子树,子元素无法通过 pointer-events: auto 恢复,应移出 DOM 或分离可点击区域。

点击穿透不是“点穿了”,是事件没被正确拦截
响应式导航栏收起后,用户点在原菜单位置却触发了下层按钮——这不是 bug,而是你用 visibility: hidden 或 opacity: 0 隐藏了导航栏,但没关掉它的事件捕获能力。浏览器照常把点击分发给它,哪怕它“看不见”。pointer-events: none 才是真正让元素退出事件流的开关。
为什么给父容器设 pointer-events: none 后子按钮还是点不了
因为事件捕获是自顶向下的:只要父级(比如 .nav-overlay)设了 pointer-events: none,整棵子树都会被跳过,不管子元素写没写 pointer-events: auto。这不是兼容性问题,是所有现代浏览器一致的行为。
- 错误写法:
.nav-overlay { pointer-events: none; }+.nav-overlay .close-btn { pointer-events: auto; }→ 按钮无效 - 正确写法:把关闭按钮移出
.nav-overlayDOM 结构,和它平级;或只对遮罩的“背景区域”设none,用伪元素或额外 div 分离可点击区域 - 更稳妥的做法:直接用
display: none隐藏整个导航栏,它天然不参与任何事件
移动端点击穿透常被混淆的两件事
一是 300ms click 延迟导致的误操作(跟 pointer-events 无关),二是真实事件穿透(比如蒙版消失瞬间,下层按钮被连带触发)。后者才是你要调的。
- 别用
pointer-events: none来“防 300ms 延迟”——它压根不影响 touch 事件延迟 - 检查是否同时绑了
touchstart和click,重复监听可能造成冒泡混乱,看起来像穿透 - iOS Safari 13.4 以下对
input元素内嵌在pointer-events: none容器中时,软键盘可能不弹出
动画过渡期最容易漏掉的关键一步
用 opacity + pointer-events: none 做淡出动画时,如果只在开始时加 none、结束时不移除,会导致整个过渡期用户点不到任何东西。
立即学习“前端免费学习笔记(深入)”;
- 必须在 CSS 动画结束回调里,用 JS 移除
pointer-events: none(或切换 class) - 不要依赖
transitionend监听opacity,某些浏览器在硬件加速下可能不触发;建议监听transform或用setTimeout保守兜底 -
display: none不能做 CSS 动画,visibility: hidden不支持过渡,所以opacity+pointer-events组合仍是动效场景最实际的选择
pointer-events: none”,而是你改的 CSS 选择器根本没命中目标元素——比如写了 .nav .open(后代选择器),但 JS 是对 <nav class="nav open"></nav> 切换类名,实际需要的是 .nav.open(无空格)。


















