css动画生效取决于属性值是否真实变化,应通过类名切换而非直接改style触发;transition须写在基类,进出动画需成对定义起止状态,并用requestanimationframe或transitionend精准控制时机。

用 transition 配合类名切换控制动画触发时机
CSS 动画是否生效,不取决于有没有写 transition,而取决于「属性值是否真的变了」。直接在元素上写 transition: all 0.3s,但靠 JS 改 style.opacity 或 style.transform,往往动不了——因为浏览器可能合并多次 style 修改,或跳过重绘判断。
正确做法是:用类名切换(element.classList.add('fade-in'))来触发动画,把过渡逻辑完全交给 CSS。
-
transition必须写在「初始类」或「通用基类」里,不能只写在目标类中(否则进入时无过渡) - 离开动画需要「离开类」保留过渡定义,并配合
setTimeout在动画结束后移除类(否则样式立刻回退) - 避免对
display做过渡——它不可动画,display: none会直接中断动画过程
进出动画必须分开定义起始/结束状态
一个常见错误是只写 .fade { opacity: 0; transition: opacity 0.3s; },然后靠 JS 切换 fade 类实现显隐——这只能做「离开」,没有「进入」效果,因为初始状态没定义透明度。
必须成对设计:
立即学习“前端免费学习笔记(深入)”;
- 进入前:
.my-component { opacity: 0; transform: translateY(10px); } - 进入中:
.my-component.entering { opacity: 1; transform: translateY(0); } - 离开中:
.my-component.leaving { opacity: 0; transform: translateY(10px); } - 所有状态都需声明
transition(通常放在基类)
示例基类:.my-component { transition: opacity 0.3s, transform 0.3s; }
JS 控制类名切换的节奏容易错在「时机」
动画帧和 JS 执行不是同步的。直接 el.classList.add('entering'); el.classList.remove('leaving'); 可能被浏览器优化掉中间态,导致无动画。
- 进入动画:先加「进入类」,不删旧类;等下一帧再删「隐藏类」(可用
requestAnimationFrame或setTimeout(..., 0)) - 离开动画:先加「离开类」,再监听
transitionend事件,在回调里移除「离开类」和内容本身(或加display: none) - 务必检查
event.propertyName,避免多个 transition 同时触发时误处理(比如只关心opacity就过滤掉transform)
兼容性与性能坑:不要过渡所有属性
transition: all 0.3s 看似省事,实则危险——它会尝试过渡每个可变 CSS 属性,包括那些不触发重绘但触发重排的(如 height、width),或根本不可过渡的(如 z-index、display)。
- 只列明需要过渡的属性,例如:
transition: opacity 0.3s, transform 0.3s -
transform和opacity是 GPU 加速友好属性,其余多数会触发 Layout / Paint,卡顿明显 - IE10+ 支持
transition,但不支持transitionend的propertyName字段,需降级为字符串匹配
复杂交互动画真正难的不是写出来,而是让每次类名切换都精准落在渲染帧边界上,且不被样式覆盖、不被 JS 干扰、不因属性误选拖慢主线程——这些细节一漏,动画就“卡一下”或者“闪一下”,用户感知比没动画还差。










