transition必须写在基础选择器中而非:hover里,否则移出时无动画;JS切换class需保持transition声明持续存在;动态插入元素要确保transition在首次渲染前已生效;避免使用不可过渡属性和transition: all。

transition写在:hover里导致移出时无动画
鼠标悬停时有过渡,一移开就“啪”地跳回原状,说明transition被错误地塞进了:hover规则里。浏览器只在伪类激活时才读到这个声明,离开后上下文清空,自然没有过渡可执行。
用 DevTools 的 Computed 面板检查transition-property:如果它只在:hover状态下显示值,常态下是<code>none,那就坐实了这个问题。
- ✅ 正确写法:
.btn { transition: opacity 0.2s; }+.btn:hover { opacity: 0.7; } - ❌ 错误写法:
.btn:hover { opacity: 0.7; transition: opacity 0.2s; } - 别依赖继承或全局重置——
transition必须显式出现在基础选择器中
JS切换class时transition声明被临时移除
调用classList.remove("fade-out")再classList.add("fade-in"),等于把transition连同状态类一起删掉了。浏览器失去起始值参考,只能硬切终态,第二次再切才“有上下文”可插值。
这不是浏览器 bug,而是样式计算的必然结果:过渡需要持续存在的transition声明,不是一次性的开关。
立即学习“前端免费学习笔记(深入)”;
- ✅ 把
transition抽到一个永不被移除的基础类里,例如:.animatable { transition: opacity 0.4s, transform 0.3s; } - 状态类只管数值:
.animatable--hidden { opacity: 0; }、.animatable--shown { opacity: 1; } - 避免在 JS 中直接写
el.style.transition或el.style.opacity,这会覆盖 CSS 规则
元素动态插入后首次过渡缺失
appendChild()后立刻加active类,浏览器把 DOM 插入和样式计算压在同一帧,根本没机会捕获“起始快照”。表现就是新元素直接显示,Computed面板里transition为none或0s。
这不是transition写错了,是时机没对上。强制重绘能解决,但得用对方式。
- 先加基础类(含
transition和初始值),再appendChild,最后用void el.offsetWidth触发重排 - 或者用
requestAnimationFrame延迟设目标状态:el.classList.add("initial"); requestAnimationFrame(() => el.classList.add("target")); - ⚠️ 别在
requestAnimationFrame回调里读getComputedStyle或offsetHeight,会打断渲染流水线
不可过渡属性导致“看似动了实则跳变”
height: auto、display: none → block、font-size(旧版 Firefox)这些属性本身不支持插值。浏览器没法算中间帧,只能瞬移。你看到的“只生效一次”,其实是每次都在失败。
DevTools 里transition看起来正常,但Computed中的transition-property可能已退化为none,尤其当all里混入了不可过渡属性时。
- 高度过渡改用
max-height(设一个足够大的固定值)+overflow: hidden - 显隐推荐组合:
opacity+visibility+pointer-events - 绝对避免
transition: all 0.3s——某个属性失效,整条声明静默降级


















