transition不触发的根本原因是浏览器未捕获初始状态,需在基础类中显式声明起始值、transition属性及正确挂载顺序,避免依赖默认值或动态赋值。

动态插入的元素上 transition 不触发,不是 CSS 写错了,而是浏览器根本没机会“看到起点”——它需要明确的初始样式、正确的挂载顺序、以及不被破坏的渲染上下文。
transition 必须写在基础类里,不能只靠 .active 或 :hover
很多人把 transition 放在功能类中,比如:.box.active { opacity: 1; transition: opacity 0.3s; }。这会导致:移除 .active 后,transition 声明就没了;再加回去时,浏览器已错过初始化时机,直接跳变。
- 正确做法是把
transition和起始值一起写进基础类:.box { opacity: 0; transition: opacity 0.3s; } - 功能类只管终值:
.box.active { opacity: 1; } - 避免在 JS 中用
el.style.transition = "..."动态赋值——它发生在渲染后,无效
先加 class,再 appendChild,否则“赶不上首帧”
浏览器对新节点的样式计算和布局会在一次渲染帧内完成。如果先 appendChild(el),再 el.classList.add("fade-in"),多数情况下(尤其是 Firefox 和 Safari)会合并操作,跳过过渡。
- 必须严格按顺序:
el.classList.add("fade-in"); container.appendChild(el); - 如果逻辑上必须先挂载(比如依赖父容器尺寸),可在
appendChild后立即触发重排:el.offsetHeight;(读取布局属性即可) - Vue / React 等框架中,确保 class 是在元素挂载前就存在的,而不是挂载后异步添加
初始值没显式声明,浏览器就“不知道从哪开始动”
opacity 默认是 1,transform 默认是 none,但这些“默认”不等于“可插值起点”。如果基础类里没写 opacity: 0,而只靠 .active { opacity: 1; },第一次变化就是 1 → 1(无变化)或 auto → 1(不可插值)。
- 所有参与过渡的属性,必须在基础类中显式写出数值起点:
height: 0、transform: translateY(-10px)、max-height: 0 - 特别注意
height: auto无法过渡,改用max-height或transform: scaleY() - Flex 子项的
width常被算成auto,需配合min-width锚定,或直接用transform
scoped 样式、display 切换、sticky 高度都会悄悄破坏 transition
这些不是“兼容性问题”,而是特定机制与 transition 的底层要求冲突:
- Vue
会让动态插入的节点不匹配选择器——用:deep(.dynamic-item)(Vue 3)穿透,或把过渡样式提到全局块 -
display: none → block不触发 transition,因为display本身不可动画——改用opacity+visibility或transform -
position: sticky元素若从height: auto变到具体像素,过渡失效——必须让初始height是确定值(如通过 JS 测量后设为 px)
最易被忽略的一点:transition 生效的前提,是浏览器在首次渲染该元素时,已经完成了样式解析、布局计算,并且目标属性有明确的、可插值的起止值。任何打断这个链条的操作——比如延迟加 class、依赖隐式默认值、或用不可过渡属性做开关——都会让动画彻底静默。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











