必须写 animation-fill-mode: forwards,但单独写这一行几乎无效,根本原因是浏览器未获取到可保持的终值,常见问题包括关键帧缺失100%、样式覆盖、animation简写重置、js触发时机不当及终态属性未显式声明。

必须写 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 动态添加动画 class 后立刻移除,forwards 就失效
刚加 class 就 remove,动画根本没走到“结束”,forwards 永远不触发;animationend 触发时,渲染可能尚未完成,getComputedStyle(el).transform 仍返回中间值;建议用 requestAnimationFrame 延迟一帧再读。
用 el.style.animation = 'none' 强制终止,会丢弃 forwards 效果,元素回归内联样式或层叠值。
真正容易被忽略的是:forwards 只影响渲染层,不更新计算样式——所以 getBoundingClientRect() 或 :hover 判断可能失准,需要 JS 固化最终值才能可靠交互。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











