pointer-events: none 仅对声明它的元素本身生效,不继承、不传染,需精准作用于真正遮挡目标的 dom 节点,伪元素和空容器也需单独设置。

pointer-events: none 能穿透点击,但只对**声明它的那个元素本身**生效——加错节点、漏掉伪元素、父层设了却不管子层,90% 的失效都出在这儿。
必须作用于真正遮挡目标的 DOM 节点
浏览器事件捕获是自顶向下走渲染树的,pointer-events: none 不会“传染”给子元素,也不会跳过父容器去影响子节点。比如遮罩结构是 <div class="dialog"><div class="mask"></div></div>,你只给 .dialog 加了 none,那 .mask 依然拦截点击。
- 用 Chrome DevTools 的「Rendering」面板勾选 Hit test borders,一眼看出哪一层实际覆盖了点击坐标
- 右键点击失效区域 → 「检查元素」,跳转到的节点大概率就是真正在挡路的那个
- 重点排查空
<div>、<code><section></section>或仅靠width/height占位却没内容的容器 - 伪元素
::before/::after默认参与事件流,得单独加pointer-events: none - 可行方案一:把按钮提为遮罩的兄弟节点,例如
<div class="mask"></div> <button class="close-btn">×</button>,再用z-index和position: absolute控制视觉层级 - 可行方案二:用 React/Vue 的 Portal 渲染到
下,彻底脱离遮罩 DOM 树 - 若必须保留在遮罩内部,需确保该按钮区域没有被其他
none层级覆盖(比如外层.dialog没设none,只设在.mask上) - 用
opacity做淡入时,不能只在起始/结束态切pointer-events—— 中间帧若仍为auto,用户可能点中半透明状态下的遮罩 - 动画开始前立即设
pointer-events: none,结束回调里再切回auto或移除该声明 - 滚动穿透不是给遮罩设
none,而是给遮罩下方的可滚动容器(如.page-content)动态加pointer-events: none - iOS 旧版 Safari 对
<input>下方压着none层时,软键盘可能不弹;真机测试必做
遮罩里有关闭按钮?别信“父 none + 子 auto”
pointer-events: none 是硬拦截:父元素设了,整棵子树在事件捕获阶段就被跳过,子元素写 pointer-events: auto 在绝大多数浏览器里完全无效。
移动端和动画中容易踩的时机坑
iOS Safari 和部分安卓 WebView 对 pointer-events: none 的支持基本稳定,但失效往往不是属性本身的问题,而是时机或组合错误。
最常被忽略的一点:哪怕元素视觉上完全透明(opacity: 0)或隐藏(visibility: hidden),只要没加 pointer-events: none,它就仍在吃点击——这和 display: none 的行为有本质区别。











