animation-fill-mode默认为none,导致动画结束后样式闪回原始状态;需显式设置forwards并确保keyframes中100%帧完整声明所有目标属性,否则无法保持末帧效果。

animation-fill-mode 默认是 none,不是 bug 是设计
动画播完立刻“闪回”原始样式,不是你写错了 @keyframes,而是 CSS 规范明确要求:除非你主动干预,否则动画只在播放期间生效。默认的 animation-fill-mode: none 意味着动画一停,所有由 @keyframes 声明的样式(比如 transform、opacity)全部撤掉,元素退回到它原本的 CSS 状态。
forwards 必须显式写,且关键帧要写全 100%
加 animation-fill-mode: forwards 才能让元素停在最后一帧,但光写这句不够:
- 必须确保
@keyframes里有明确的100%或to块,且里面声明了你想保留的所有属性——比如动画中改了transform和opacity,那100%里就得都写上,漏一个就不会保持 -
forwards不会“补全”未声明的属性,也不会继承元素原有transform值;如果原元素有transform: scale(0.9),而动画只写了transform: translateX(100px),结束时scale就会变成none - 简写进
animation属性也行:animation: slideIn 0.4s ease forwards;,但别漏了分号后的空格,否则部分浏览器可能解析失败
forwards 不生效?先查这三个地方
写了 forwards 还闪回,大概率卡在这三处:
-
animation-iteration-count不是1:设成infinite或没显式声明,会导致“每次循环结束都停在末帧”,但视觉上仍是反复动;真要“播一次就定住”,得配animation-iteration-count: 1 - 被更高优先级样式覆盖:比如动画结束后,另一个 class 又写了
opacity: 0,或内联样式style="opacity: 0",直接压过forwards的效果;用开发者工具看Computed面板,确认最终生效的是哪条 - 用了
animation-direction: alternate却没限制循环次数:来回播两轮后,forwards会停在反向的最后一帧(即0%),看起来像回退了——这种情况应配animation-iteration-count: 1或改用normal
别拿 animation-fill-mode 当 transition 的替代品
animation-fill-mode 只管 @keyframes 动画的生命周期边界,和 transition 完全是两套逻辑:
立即学习“前端免费学习笔记(深入)”;
-
transition结束后状态“弹回去”,是因为目标值没真正落地——比如只在:hover里写了opacity: 0.5,鼠标一移开,值就没了;这时得在常态选择器里也写上终态,或用 JS 固化element.style.opacity = "0.5" -
forwards对transition完全无效,它不响应属性变化,也不参与过渡过程 - 两个同时存在时,
transition控制属性变化的中间过程,animation控制预设路径,fill-mode只作用于后者
最常被忽略的一点:forwards 保的只是你写死在 100% 里的那些声明,它不会“记住”动画前的状态,也不会“合并”其他 transform。想让多个变形共存,得在关键帧里手动拼接,比如 transform: scale(0.9) translateX(100px)。


















