animation-fill-mode 默认为 none 是规范行为,动画结束后样式立即还原;需显式设 forwards 并确保 100% 帧声明全部目标属性,简写 animation 中必须包含 forwards 才生效。

animation-fill-mode 默认是 none,不是 bug 是规范行为
动画播完立刻“闪回”原始样式,不是你写错了 @keyframes,而是 CSS 规范明确要求:除非你主动干预,否则动画只在播放期间生效。默认的 animation-fill-mode: none 意味着动画一停,所有由 @keyframes 声明的样式(比如 transform、opacity)全部撤掉,元素退回到它原本的 CSS 状态。
加 forwards 必须显式写,且 100% 帧要写全所有目标属性
animation-fill-mode: forwards 不会“补全”未声明的属性,也不会继承元素原有 transform 值。如果原元素有 transform: scale(0.9),而动画只写了 transform: translateX(100px),结束时 scale 就会变成 none。
- 必须确保
@keyframes里有明确的100%或to块,且里面声明了你想保留的所有属性 - 移动端建议显式写
100%,部分老旧 Android WebView 对to解析不稳定 - 不要用简写
transform混合多个值却只在关键帧里改其中一部分
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 里漏写 forwards,等于白加
animation 简写会重置所有未写出的子属性,包括把 animation-fill-mode 强制设回 none。单独声明 animation-fill-mode: forwards 很容易被覆盖或遗漏。
- ✅ 正确写法(推荐):
animation: slideIn 0.4s ease forwards;(注意分号前有空格) - ❌ 错误写法:
animation: slideIn 0.4s ease;+ 单独一行animation-fill-mode: forwards; - JS 动态设置时,别只改
element.style.animation,记得同步设element.style.animationFillMode = 'forwards'
forwards 生效,它也只维持动画结束那一刻的计算值;如果动画依赖视口尺寸、父容器变化或媒体查询,这些外部变动仍会触发重排,让“保持住的样式”看起来又变了。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











