animation-fill-mode: forwards 仅对完整执行完毕的动画生效,若被 paused 或 js 修改 animation 属性则失效;需确保动画自然结束,暂停用 animationplaystate,读取状态用 getcomputedstyle 和 dommatrix。

animation-fill-mode: forwards 为什么没生效
动画结束后元素回到初始位置,不是因为 animation-fill-mode 写错了,而是它只对「已开始且已结束」的动画起作用——如果动画被 animation-play-state: paused 中断,或中途被 JS 修改了 animation 属性(比如重设 animation-name),forwards 就不会保留最终状态。
- 确保动画完整执行完,而不是靠
setTimeout手动停在某一帧 - 避免用 JS 直接改
style.animation,改完会重置整个动画上下文;要用style.animationPlayState = 'paused'暂停,再配合getComputedStyle(el).transform读取当前值做快照 -
forwards不影响transform的层叠逻辑:如果动画里设置了transform: translateX(100px),但元素本身有style.transform = 'scale(0.9)',最终只会保留动画里的值,原始内联样式会被覆盖
transition + transform 替代 animation 时的位置残留
用 transition 切换 class 触发位移,动画停了但位置“卡住”,大概率是 class 移除后,元素又回到了未加 transition 的原始样式,而 transition 并不保留终点值。
- 别依赖 class 移除来“回退”,而是显式写一个「结束态 class」,比如
.moved和.moved-final,后者带最终transform值和transition: none - 如果必须动态控制,JS 设置完
el.style.transform = 'translateX(200px)'后,立刻加一句el.style.transition = 'none',再用requestAnimationFrame下一帧恢复 transition,防止回弹 - 注意
transform值不能混用单位:动画里是translateX(50%),JS 手动设成translateX(200px),浏览器会丢弃百分比计算上下文,导致错位
JavaScript 强制重排触发的视觉错位
动画结束后用 JS 读 offsetLeft 或写 style.left,可能强制同步布局,打断浏览器对合成层的优化,让本该静止的元素“闪一下”或偏移。
- 优先读
getComputedStyle(el).transform,它返回矩阵字符串,比offsetTop更可靠;解析可用new DOMMatrix(...) - 避免在动画进行中反复读写 layout 触发属性(
offsetHeight、clientWidth等),尤其不要放在requestAnimationFrame回调里循环读 - 如果真要获取动画结束位置,监听
animationend事件后,用getComputedStyle+DOMMatrix提取 translate 值,再设为内联transform并关掉 animation










