transition必须写在元素默认状态中,而非仅:hover或.active里;用opacity+transform替代display/height;监听transitionend需过滤propertyName;确保元素已挂载且起始/结束值不同。

transition写在基础样式里,别只塞:hover或临时class里
鼠标移上去有动画、一挪开就“啪”一下跳回——这不是浏览器问题,是transition没写对位置。它必须声明在元素的默认状态中(比如.skeleton或.card),而不是仅放在:hover或JS切换的.active里。
常见错误:.btn:hover { transition: opacity 0.3s; }——移出时规则失效,动画直接丢弃。
正确写法:.btn { transition: opacity 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); },再配.btn:hover { opacity: 0.7; }。
多个属性要过渡?分开写更可控:transition: transform 0.25s, opacity 0.3s;,避免用all引入意外变化。
立即学习“前端免费学习笔记(深入)”;
用opacity + transform替代display或height:auto
display: none和height: auto完全不可动画——写了也不动,还会干扰渲染流。骨架屏切换内容时,常见错误是用display控制显隐,结果只有“闪现”,没有过渡。
正确做法是组合使用:
- 初始状态设
opacity: 0; transform: translateY(10px); - 目标状态设
opacity: 1; transform: translateY(0); - CSS中只声明这两个属性的
transition,不碰height或visibility
注意:transform和opacity是唯二能稳定触发GPU加速的属性;其他如background-color在深色模式或低端设备上易卡顿。
监听transitionend时必须过滤propertyName
一个元素同时过渡transform和opacity,transitionend会触发两次。不加判断就执行后续逻辑,容易重复调用或状态错乱。
必须检查e.propertyName,只响应目标属性:
element.addEventListener('transitionend', (e) => {
if(e.propertyName === 'opacity') {
// 这里处理透明度动画结束,比如移除骨架类
}
});
注意:transitionend不冒泡,得绑定在目标元素本身;也别依赖setTimeout等时间点,GPU就绪延迟或缩放设置都可能导致偏差。
骨架屏切换前必须确保元素已挂载且可绘制
很多过渡失效,不是CSS写错,而是DOM状态没“动起来”:元素刚createElement完还没append(),或者被display: none压根没进渲染树,浏览器快照拍不到它。
关键检查点:
- 骨架元素必须已插入DOM(
el.parentNode !== null) - 不能是
display: none或visibility: hidden;哪怕opacity: 0.001也比彻底隐藏强 - 起始值和结束值必须不同(比如
opacity: 0 → opacity: 1) - JS中切换class后,若动画不触发,补一句
void el.offsetWidth强制同步重排
真正难的不是写几行transition,而是让浏览器在正确时机拍到“旧帧”和“新帧”——骨架屏退场、真实内容入场之间,必须留出一次布局计算机会,否则动画直接跳过。



















