transition结束后子元素点不了,主因是父元素display: none未恢复、transform导致点击区域错位、transitionend事件监听失效或伪元素拦截事件,需分别用display显式切换、避免transform控制显隐、加事件兜底及设pointer-events: none修复。

transition结束后子元素点不了,大概率是父元素display: none没恢复
过渡动画本身不会让子元素失焦,但常见误操作是:用opacity或transform做隐藏时,忘了同步控制display。比如父容器设了opacity: 0再加transition,动画结束时虽然视觉上“出现”了,但display仍为none——子元素根本不在渲染树里,自然无法响应事件。
必须确保:过渡完成后的终态样式中,display值是block、inline-block等有效值,不能留空或继承自隐藏状态。
- 错误写法:
.box { opacity: 0; transition: opacity 0.3s; } .box.active { opacity: 1; }→ 缺少display显式声明,若初始是display: none,.active类不会自动恢复它 - 正确写法:
.box { display: none; opacity: 0; transition: opacity 0.3s; } .box.active { display: block; opacity: 1; } - 更稳妥的做法:把
display切换和opacity过渡拆成两个独立步骤,用animationend或transitionend事件在动画结束后再设display: block
子元素被父元素的transform“带偏”了点击区域
如果父元素用了transform: scale(0.95)或translateZ(0)触发动画,它会创建新的层叠上下文(stacking context),且部分浏览器(尤其是 Safari)在计算子元素 hit area 时,会基于变换前的几何框快照,导致点击坐标映射错位。
这不是子元素“失效”,而是浏览器没及时更新事件坐标系。此时即使pointer-events: auto开着,点击也会落空。
立即学习“前端免费学习笔记(深入)”;
- 验证方式:打开 Chrome DevTools → Rendering 面板 → 勾选
Hit test borders,看点击热区是否和视觉位置对齐 - 临时修复:给父元素加
will-change: transform,提示浏览器提前准备合成层,减少坐标计算延迟 - 根治方案:避免用
transform控制显隐逻辑;改用opacity + display组合,或把可点击子元素提到父级外层 DOM
transitionend事件没监听到,导致pointer-events没及时恢复
很多同学在动画结束时靠transitionend来设pointer-events: auto,但这个事件有三个坑:一是它不触发于display: none元素(Safari 15.4 之前);二是多个属性同时过渡时,可能触发多次;三是如果中途手动移除了类,事件就丢了。
不能只信transitionend,得加兜底。
- 监听时加
once: true防止重复执行:el.addEventListener('transitionend', handler, { once: true }) - 加一个
setTimeout容错,时间略大于transition-duration(比如多加 50ms) - 如果用了
classList.toggle(),记得在toggle前先确保pointer-events是none,避免并发修改冲突
伪元素::before/::after在挡路却没被发现
哪怕只是加了个阴影、边框或背景渐变,::before和::after默认也参与事件流。它们没有z-index,但会盖在子元素上,而且开发者工具里经常看不到——右键点击失效区域,“检查元素”跳转到的往往是父容器,不是伪元素本身。
伪元素不继承pointer-events,必须单独设。
- 快速排查:在 DevTools 的 Computed 面板搜
pointer-events,确认伪元素的值是不是auto - 通用写法:
.parent::before, .parent::after { pointer-events: none; } - 如果伪元素需要 hover 效果,又不想拦截点击,就拆成两个层:一个纯视觉的伪元素 + 一个透明但
pointer-events: auto的空div覆盖其上


















