animation-fill-mode 默认值为 none,即动画结束后立即丢弃关键帧样式并回退到原始 css 值;forwards 将最后一帧样式写入计算样式,backwards 在 delay 期间应用首帧样式,both 是二者组合,但均需显式声明且依赖动画实际触发与完成。

animation-fill-mode 默认值是 none,不是“没写就不管”,而是“明确丢弃动画样式”
很多人以为不写 animation-fill-mode 就是“随缘保留”,其实浏览器严格按 none 执行:动画一停,所有 @keyframes 里定义的样式(比如 transform、opacity、color)立刻失效,元素瞬间回退到非动画状态下的原始 CSS 值。这不是 bug,是规范行为。
常见错误现象:
- 淡出动画结束后元素又突然显示出来
- 滑入动画播完后元素“弹回”左侧原点
- 用
animation: fade-out 0.2s;简写,结果opacity: 0根本没留住
根本原因:简写 animation 会把未显式声明的 animation-fill-mode 强制重置为 none。所以哪怕你写了 100% { opacity: 0; },没配 forwards,它就是无效的。
forwards 不是“让动画多停一会儿”,而是“把最后一帧样式真实写进计算样式”
forwards 的作用不是延长动画时间,而是让浏览器在动画结束后,把最后一帧(100% 或 to)中声明的属性,当作当前元素的“有效样式”持续应用。它影响的是 getComputedStyle() 返回的结果,也影响后续其他 CSS 规则的层叠逻辑。
使用场景和限制:
- 适用于单次播放或有限循环(
animation-iteration-count: 1或3),此时“结束”有明确定义 - 对
infinite动画无效——因为没有“结束”,forwards不触发 - 如果动画本身有
animation-play-state: paused,forwards依然生效:暂停在哪儿,就冻结在哪儿 - 注意优先级:
forwards冻结的样式,仍可能被更高权重的普通 CSS 覆盖(比如内联style="opacity: 1")
backwards 只在 animation-delay 期间起作用,且依赖 first keyframe 定义
backwards 不是“提前播放动画”,而是在 animation-delay 持续期间,把第一帧(0% 或 from)的样式提前应用到元素上。一旦延迟结束、动画真正开始,这个效果就自动退出。
典型用法和易错点:
- 常用于“准备态”视觉衔接:比如一个按钮 hover 后延迟 0.2s 才弹出 tooltip,用
backwards让 tooltip 在 delay 阶段就处于opacity: 0、transform: scale(0.9)等起始状态,避免闪现 - 必须配合
animation-delay才可见效果;没设 delay,backwards等同于none - 如果
@keyframes里没写0%,浏览器会尝试从100%反推,但结果不可靠——务必显式定义0%帧 -
backwards不影响动画结束后状态,它只管“开始前那段时间”
both 是 forwards + backwards 的组合,但不是简单叠加
both 表示:在 animation-delay 阶段应用 0% 样式,在动画结束后保持 100% 样式。但它不等于“全程都用动画样式”——动画正在播放时,它照样走完整关键帧流程。
实际效果取决于两个时间点是否重叠:
- 如果
animation-delay: 0.5s,动画时长0.3s,那么0.5s内用0%样式,接着0.3s播放动画,最后永久保留100%样式 - 如果动画有
animation-iteration-count: infinite,both中的forwards部分失效,只剩backwards在 delay 阶段起作用 - 不要指望
both能绕过简写覆盖问题:仍需在animation简写中显式包含both,否则会被重置为none
真正容易被忽略的是:animation-fill-mode 的生效前提是动画“被触发且完成/暂停”,如果元素还没挂上动画(比如 class 还没加)、或动画被 JS 中断(el.style.animation = ''),它就完全不参与计算。别只盯着取值,先确认动画真正在跑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











