animation-fill-mode: forwards 不会覆盖 :hover,但会将动画终态写入计算样式并持久保留,导致 hover 移出后样式卡在终态;解决方法是用 transition 替代或显式重置属性。

animation-fill-mode: forwards 本身不会“覆盖” :hover,但它会让动画结束后的样式写入计算样式,从而在 hover 状态解除后,仍维持终态 —— 这个行为和 :hover 规则的层叠逻辑冲突时,视觉上就像 “hover 失效了”。
forwards 写在 :hover 里,但鼠标移开后状态还在
这是最常见误解:你本意是“hover 时播放动画,移开就恢复”,却写了 .btn:hover { animation: slideIn 0.3s ease forwards; }。结果动画播完,forwards 把 transform: translateX(100px) 永久写进元素的计算样式里。一旦鼠标移出,:hover 规则失效,但 forwards 锁住的样式还在,于是元素卡在右边不动。
- 根本不是
:hover被覆盖,而是:hover结束后,forwards的终态仍在生效 - 浏览器没删掉那个
transform值,它现在是“当前有效样式”的一部分 - 除非你手动重置(比如加一个
.btn:not(:hover) { transform: none; }),否则它不会自动退
同一属性被 forwards 和 :hover 同时控制,优先级混乱
比如 :hover 里设了 opacity: 0.8,动画关键帧里也改了 opacity,且用了 forwards。动画播完后,opacity: 0.8 被锁住;此时再 hover,:hover 的 opacity: 0.8 和已锁定的值一样,看不出变化;若 hover 改的是 opacity: 1,那它能覆盖 —— 但前提是它的选择器权重 ≥ 动画终态的隐式权重(后者等效于内联样式级别)。
-
forwards锁定的样式,在 computed 样式中表现为“来自动画”,优先级高于普通类,接近内联样式 -
:hover规则若没用!important或更高权重,可能压不过forwards已固化的值 - 特别危险的是
transform:动画只写translateX(50px),forwards锁住后,:hover再写scale(1.1)会合并失败(浏览器不自动补全原始transform值)
想让 hover 动画可逆,别依赖 forwards
如果目标是“hover 进来动一次,移开退回”,forwards 是反模式。它专为「单向不可逆动效」设计(比如入场、提示消失、按钮点击反馈)。可逆交互该用 transition。
- 把动画逻辑换成
transition: transform 0.3s ease;,基础样式写transform: translateX(0);,:hover写transform: translateX(100px); - 或者用 JS 在
animationend后主动清除类名,避免forwards滞留 - 真要用
forwards+:hover,必须在非 hover 状态下显式重置所有被动画过的属性,例如:.btn { transform: none; opacity: 1; }
最常被忽略的一点:forwards 不是“暂停动画”,它是把关键帧里的声明硬塞进元素的最终样式快照里 —— 这个快照不会因为 :hover 离开而自动销毁,得你亲手清。










