transition是状态驱动的平滑过渡,仅在属性值变化时生效,适用于明确起点终点的交互反馈;animation是时间轴驱动的独立播放器,支持多阶段、循环、倒放等复杂控制,适用于自动播放的视觉叙事。

transition 是状态变化的“平滑连接线”
它不自己动,只在 CSS 属性值真正改变时(比如 :hover、class 切换、JS 改 style.opacity),把两个确定状态之间“拉一条缓动曲线”。没有变化,它就安静待着。
常见误用:transition: all 0.3s 一加,所有属性全被拖进过渡队列;鼠标快速进出时,height 或 margin 被卷入,直接触发重排卡顿;display、height: 0 → auto 这类不可计算的属性,transition 完全不生效。
实操建议:
- 只对可动画属性用:优先选
transform、opacity,避免改width、left、margin - 明确指定属性:写
transition: transform 0.2s, opacity 0.2s,别偷懒用all - 必须显式变更才触发:class 存在但值没变,不会启动;JS 改
style.transform才算数
animation 是时间轴驱动的“独立播放器”
它靠 @keyframes 定义帧序列,加载即播、可循环、能暂停、支持 animation-direction: reverse 倒放、animation-fill-mode: forwards 保持终态——这些 transition 全都没有。
典型翻车点:animation: pulse 1s infinite 写在 :hover 上,结果每次移入都重头播放,UI 抽搐;忘了加 forwards,动画一结束立刻回退,视觉断层。
实操建议:
- 需要自动播放、循环、倒放、延迟时,必须用 animation
- 多阶段动效(比如“旋转→缩放→抖动”)只能靠 keyframes 分段控制
- IE10+ 支持,但老 Android WebView 对
cubic-bezier()解析不准,生产环境建议用ease、linear
混用时怎么避免互相打架?
两者不是二选一,而是分工协作:transition 处理用户操作带来的状态变化,animation 实现独立节奏的视觉反馈。但直接叠加容易出问题。
例如按钮悬停时既要缩放又要呼吸灯,如果只写:
.btn:hover {
transform: scale(1.1);
animation: pulse 1s infinite alternate;
}
会导致每次 hover 都重播 pulse,且无法暂停。正确做法是分离控制逻辑:
- 缩放用
transition: transform 0.3s,由 hover 触发 - 呼吸灯用独立 class 控制:
.pulse-running { animation: pulse 1s infinite alternate; } - JS 在
mouseenter时添加pulse-running,mouseleave时移除或设animation-play-state: paused
伪元素(如 ::after)可单独跑发光动画,不影响主元素的 transition 流程。
调试时怎么看谁在起作用?
Chrome DevTools 的 Animations 面板能分别列出当前激活的 transition 和 animation,还能逐帧预览、手动暂停/重播。但注意:如果某条 transition 被 animation 同名属性覆盖(比如都改 transform),animation 会优先生效,而 transition 彻底失效——这点极易忽略。
真正复杂的交互里,animation 的 iteration-count 和 transition 的 delay 叠加后,时间线容易错位;更麻烦的是,JS 动态增删 class 时,若 timing-function 不一致,视觉节奏会突然跳变。这些细节,光看代码很难发现,必须真机跑起来调。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











