animation-fill-mode: forwards 仅锁定关键帧中显式定义的终态样式,若@keyframes缺100%帧、动画未真正结束或被高优先级样式覆盖,便会失效;须确保关键帧写全、动画正常完成且fill-mode与animation同级声明。

animation-fill-mode: forwards 能让动画结束后保持最后一帧样式,但光写这一行大概率失效——它只是“锁住”关键帧里明确写出的值,不负责补全、不覆盖高优先级样式、也不保证动画真结束了。
为什么写了 forwards 还是闪回原位?
根本不是 CSS 写错了,而是浏览器按规范执行:没显式定义的属性,forwards 就锁不住。常见卡点:
-
@keyframes里漏了100%帧,比如只写了0%和50%,浏览器会用元素原始transform值“补”终态,forwards锁住的就是这个错误值 - 动画根本没结束:
animation-iteration-count是infinite,或被animation-play-state: paused暂停在中间,forwards不触发 - 更高优先级样式覆盖:比如动画后另一个 class 又设了
opacity: 0,或内联样式style="transform: none",直接压过forwards的效果
animation-fill-mode: forwards 必须和 animation 同级声明
它不是独立开关,只对正在运行的动画生效。很多人把它单独写在另一个 CSS 规则里,或者 JS 动态设置时只改 element.style.animation,忘了同步设 element.style.animationFillMode = 'forwards',结果内联样式丢掉了 fill-mode。
- 推荐用简写:
animation: slideIn 0.3s ease-out forwards;,避免遗漏 - 如果必须分开写,确保
animation-fill-mode和animation-name/animation-duration在同一选择器、同一权重下声明 - 移动端尤其注意:老旧 Android WebView 对
to解析不稳定,显式写100%更稳
transform 动画中 forwards 失效的典型原因
transform 不会自动合并,动画里只写了 translateX(100px),但元素原本有 scale(0.9),动画结束时就只剩 translateX(100px),scale 被重置为 none —— 看起来像“缩回去了”。
- 关键帧里必须写全所有要保留的
transform属性:100% { transform: translateX(100px) scale(0.9); } - 同理,
opacity、visibility、height等也得在100%显式声明,不能依赖继承或初始值 - 父容器
overflow: hidden下,动画中移出可视区,但闪回会导致元素又露出来,视觉上更突兀
最易忽略的一点:forwards 只管“动画结束后的那一瞬间”,它不阻止后续 JS 修改、不干预 transition 起始值、也不解决动画本身被中断或覆盖的问题。真正想“停住”,得从关键帧完整性、动画生命周期、样式优先级三处同时检查。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











