必须显式设置animation-fill-mode: forwards,否则动画结束即回退至初始状态;它需与完整100%/to关键帧配合,并写入animation简写中或同选择器下,避免被覆盖或遗漏。

因为 animation-fill-mode 默认值是 none,动画一结束,浏览器就立刻丢掉所有关键帧里声明的样式,元素退回到它原本的 CSS 状态——这不是 bug,是规范行为。
animation-fill-mode: forwards 是唯一能“锁住”终态的解法
不写它,@keyframes 再完整也没用;写了它,才可能让 opacity、transform、filter 等保持在 100% 帧定义的值上。
- 必须显式写进 CSS 规则里,不能指望继承或父级传递
- 推荐直接塞进
animation简写中:animation: fadeIn 0.3s ease forwards;(注意分号前有空格) - 如果分开写,要确保
animation-fill-mode: forwards;和animation在同一选择器下,且后面没被重置为none
@keyframes 漏了 100% 或 to 块,forwards 就锁了个空壳
浏览器不会帮你“补全”未声明的属性。比如元素原本有 transform: scale(0.9) rotate(2deg),而动画只写了 to { transform: translateX(100px); },那结束时 scale 和 rotate 就归 none,视觉上就是“缩回原形”。
-
100%或to块必须显式写出所有你想保留的属性值 - 复合属性如
transform、filter不会叠加,只覆盖——没写的部分等于被设为初始值 - 别依赖“原始样式自动延续”,CSS 动画没有这种机制
写了 forwards 却还闪回?先查这三处
常见失效几乎都集中在这几个点:
立即学习“前端免费学习笔记(深入)”;
-
@keyframes里漏了100%或to:浏览器用元素初始值“补”终态,forwards锁住的就是这个错的值 - 被更高优先级样式覆盖:内联
style="opacity: 0"、带!important的类、或后续规则(如.disabled { opacity: 0; })都会压过forwards保持的值 -
animation-direction: alternate配合了多次循环:比如animation-iteration-count: 2,动画停在反向最后一帧(即 0%),看起来像“回去了”
JS 触发动画时最容易忽略的时机问题
刚加 class 就 remove、或在 animationend 里立刻读 getComputedStyle,都可能导致 forwards 效果“看不见”:
- 动态添加动画 class 后立刻移除,动画根本没走到“结束”,
forwards永远没机会执行 -
animationend回调里直接改样式,可能被动画层残留值覆盖;稳妥做法是先设element.style.animationName = 'none',再读offsetHeight强制重排,最后操作样式 - 重复快速添加/移除同一 class,浏览器可能跳过动画,直接应用初始样式
真正麻烦的不是加不加 forwards,而是它只管动画层,不管布局层——如果动画结束时尺寸变化影响了父容器流式布局,那种“闪回感”可能来自重排,而非样式丢失。


















