animation-fill-mode: forwards 是防止闪回的必要条件,但单独使用无效,因浏览器未获取到可保持的终值,常见原因包括关键帧缺失100%/to、样式覆盖、animation简写未显式含forwards、js触发时机不当及旧版webview兼容性问题。

animation-fill-mode: forwards 是防止闪回的必要条件,但只加这一行大概率没用——问题几乎都出在关键帧定义、样式覆盖或 JS 触发时机上。
为什么写了 forwards 还是闪回
根本原因不是属性写错了,而是浏览器没拿到“可保持的终值”。常见情况包括:
-
@keyframes里漏了100%或to块:比如只写了0%和50%,浏览器会用元素初始transform补全终态,forwards锁住的就是这个错的值 - 被更高优先级样式覆盖:内联样式
style="opacity: 0"、带!important的类、或后续 CSS 规则(如.disabled { opacity: 0; })都会直接压过forwards保持的值 -
animation-iteration-count没设为1:如果用了infinite或没声明,默认是1,但若配合animation-direction: alternate,动画结束时可能停在反向最后一帧(即0%),看起来像回退
animation 简写里必须显式包含 forwards
很多人只写 animation: fadeIn 0.3s ease;,以为 forwards 可以靠单独声明补上。但实际中,animation 简写会重置所有未显式写出的子属性,包括把 animation-fill-mode 强制设回 none。
正确写法只有两种:
- 直接写进简写:
animation: fadeIn 0.3s ease forwards;(注意分号前有空格) - 分开写,且确保
animation-fill-mode: forwards;和animation在同一选择器下,且后面没出现animation-fill-mode: none;之类重置
@keyframes 的 100% 必须写全所有目标属性
forwards 不会“补全”未声明的属性,也不会继承原始 transform 值。例如:
- 元素原本有
transform: scale(0.9) rotate(2deg) - 动画只写了
to { transform: translateX(100px); } - 那结束时
scale和rotate就归none,视觉上缩放/旋转消失
正确写法是:to { transform: translateX(100px) scale(0.9) rotate(2deg); }。同理,filter、opacity、color 等只要你想保留,就必须在 100% 或 to 中显式写出。
JS 触发时最容易忽略的三个坑
用 JS 动态添加动画 class 后立刻移除、或在 animationend 事件里马上读取 getComputedStyle,都可能导致 forwards 效果“看不见”:
- 刚加
class就remove,动画根本没走到“结束”,forwards永远不触发 -
animationend触发时,渲染可能尚未完成,getComputedStyle(el).transform仍返回中间值;建议用requestAnimationFrame延迟一帧再读 - 用
el.style.animation = 'none'强制终止,会丢弃forwards效果,元素回归内联样式或层叠值
旧版 WebView(如 Android 4.4)和 iOS Safari ≤14.1 还有兼容性问题:必须把 forwards 写进 animation 简写、全部用 100% 替代 to、禁用 alternate、并在 100% 中重复写出所有原始 transform 值——否则即使写了 forwards,也会回弹。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











