animation-fill-mode: forwards 必须与 animation 简写或 animation-name 等属性共存且写在触发动画的元素上,才能使动画结束后保持 100% 关键帧中显式声明的样式;若未完整写出 transform、opacity 等属性值,则对应样式不会保留。

animation-fill-mode: forwards 是保持结束状态的必要设置
动画播完后元素“啪”一下跳回原始位置或透明度归零,不是关键帧写错了,而是默认 animation-fill-mode: none 在起作用。哪怕 @keyframes 里写了 100% { transform: translateX(200px); opacity: 0; },只要没显式加 forwards,浏览器就只在播放过程中应用这些样式,一停就撤回。
必须同时满足两个条件才真正生效:
-
animation-fill-mode: forwards要写在触发动画的元素上(不能只靠父级继承) - 它必须和
animation或其子属性(如animation-name)共存——单独写animation-fill-mode不起作用 - 推荐用简写语法直接带上:例如
animation: slideIn 0.3s ease-out forwards;,避免被后续样式覆盖
为什么只加 forwards 还是没留住 transform 或 opacity
常见错觉是“加了 forwards 就该万事大吉”,但实际常因样式覆盖或定义不全失效:
- 如果元素原本有
transform: scale(0.8),而动画只声明了100% { transform: translateX(100px); },那动画结束后transform会变成translateX(100px),而非合并值——scale 信息彻底丢失 - 同理,
opacity、color等属性也需在100%帧中显式写出,不能依赖初始值或中间帧推断 - 别忽略
display:若动画前设了display: none,即使opacity: 1生效,元素仍不可见;改用visibility: hidden+opacity组合更稳妥
animation-iteration-count: 1 和 forwards 必须配对使用
目标是“执行一次、停在终点”,光靠 forwards 不够:
-
animation-iteration-count默认确实是1,但一旦父级或重置规则把它改成infinite或其他值,forwards仍生效,只是每次循环结束都“停在末帧”,视觉上变成卡顿或闪烁 - 显式写
animation-iteration-count: 1更安全,尤其在组件复用或 CSS-in-JS 场景下,避免隐式继承干扰 - 错误示范:
animation: fadeOut 0.5s; animation-fill-mode: forwards;→ 若某处全局设置了animation-iteration-count: infinite,这个动画就会无限循环且每次停住,而不是只播一次
backwards / both 不是“更高级”,而是解决不同时间点的问题
很多人误以为 both 是“终极方案”,其实它只管两段空白期,和动画本身无关:
-
backwards只在animation-delay存在时有效:比如animation-delay: 0.5s,又希望元素在等待这 0.5 秒时就显示0%帧的opacity: 0.2或transform: translateY(-10px),就得配backwards -
both = forwards + backwards,不是“全程生效”,它不管动画中间过程,只控制 delay 前和结束后这两段 - 典型误用:没设
animation-delay却写both→backwards部分无效,白写;想让按钮悬停动画“移上瞬间放大、松开后保持放大”,这才是both的正经用法
最容易被忽略的是:所有这些效果都依赖于关键帧中明确写出最终样式的属性值,而不是靠浏览器“猜”。forwards 不会帮你补全 transform、不会合并 color,它只忠实地保留你写在最后一帧里的那几行 CSS。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











