transition适用于用户交互触发的两个确定状态间的平滑渐变,如悬停、焦点变化;animation则用于多状态、循环、延迟或复杂节奏控制的动效,二者可共存但需避免同一属性叠加冲突。

过渡(transition)适合什么场景
过渡适合在状态切换时添加平滑的视觉反馈,比如按钮悬停、菜单展开、表单项焦点变化。它的核心是「两个确定状态之间的渐变」,必须由用户交互(如 :hover、:focus)或脚本触发 CSS 类切换来启动。
常见错误是试图用 transition 实现多阶段运动或循环效果——它只响应属性值变化,不描述过程本身。
- 适用:颜色变化、尺寸微调、透明度切换、简单位移(如
transform: translateX) - 不适用:路径动画、逐帧控制、暂停/逆向播放、多个关键帧序列
- 性能友好:优先使用
transform和opacity,避免触发布局重排(如width、height、top)
动画(animation)什么时候非用不可
当需要定义超过两个状态、循环播放、延迟启动、或精确控制中间帧节奏时,@keyframes 是唯一选择。它不依赖状态切换,可独立运行,也支持 animation-play-state 动态控制。
典型误用是给一个简单 hover 效果写满 0%–100%,既冗余又难维护。
立即学习“前端免费学习笔记(深入)”;
- 必须用:加载指示器(spin)、图标脉冲、复杂入场动效(如弹跳+缩放)、SVG 路径描边
- 注意兼容性:
animation-timing-function在旧版 Safari 中对自定义贝塞尔曲线支持不稳定 - 可搭配
animation-fill-mode: forwards保持最终帧,但别和transition同时作用于同一属性,否则行为不可预测
transition 和 animation 能否共存
能,但要小心叠加冲突。比如同时给 opacity 设置 transition 和 animation,浏览器会以 animation 为准,transition 不生效;若 animation 已结束且 fill-mode 未设为 forwards,后续 transition 才可能接管。
实际项目中更稳妥的做法是「分工明确」:用 animation 处理主动播放的动效,用 transition 处理被动响应的交互反馈。
- 避免同时声明:
transition: opacity 0.3s; animation: fade-in 1s; - 若需衔接,可用 JS 监听
animationend后再添加过渡类 - 调试技巧:在 DevTools 的 Animations 面板中可分别查看二者是否被激活、是否被覆盖
一个易忽略的细节:transition 的触发时机
transition 不会在元素首次渲染时自动播放,哪怕初始样式和目标样式不同。它只在「属性值发生改变」的那一刻开始计算——这个改变必须是「可检测的重绘事件」,比如类名切换、内联样式修改、伪类激活。
这意味着用 JS 设置初始 style.opacity = 0,再立刻设为 1,不会触发过渡;必须加个微小延迟或用 getComputedStyle 强制重排。
- 正确做法:
element.classList.add('active'); // 或 setTimeout(() => element.style.opacity = 1, 0); - 更可靠方式:用
requestAnimationFrame确保在下一帧应用变化 - Vue/React 中注意:状态更新与 DOM 更新不同步,直接在
setState后操作 DOM 可能取不到新样式










