必须用class切换+强制reflow才能真正重播动画;因animation-play-state设为running不会重置时间轴,仅续播,且ios safari等对runtime修改支持差,已停在终态时更无效。

不能靠 animation-play-state 恢复,必须用 class 切换 + 强制 reflow 才能真正重播;后台冻结时时间轴持续走,resume 只是续播,不是重播。
为什么 animation-play-state = 'running' 在 visibilitychange 里无效
浏览器冻结动画后,animation-play-state 的计算值仍可能是 "running",但帧早已停住。设回 'running' 不会重置时间轴——它只会从后台停留的秒数继续播(比如停了 18 秒,回来就跳到第 18 秒的帧)。iOS Safari(尤其微信 WebView)对 runtime 修改该属性支持极差,常忽略或延迟生效;若动画已因 animation-fill-mode: forwards 停在终态,再设 running 根本不触发新周期。
可靠重播必须三步:移类 → reflow → 加类
让浏览器“认为这是新动画”,而非唤醒旧实例。这三步缺一不可:
- 先移除动画类:
el.classList.remove('animate-fade') - 强制同步 reflow:
el.offsetHeight或getComputedStyle(el).opacity(不加这步,class 切换常被合并优化,无效) - 再添加动画类:
el.classList.add('animate-fade')
动画类中只声明 animation,且必须设 animation-fill-mode: none,避免 forwards 锁死终态样式导致无法重播。
iOS Safari 和 Android Webview 的兼容性陷阱
visibilitychange 在 iOS 上响应常延迟 200–500ms,甚至息屏时不触发;微信 WebView 还可能错报 document.visibilityState 为 'visible'。实际落地要:
- 不只监听
visibilitychange,同时加pagehide、pageshow、focus事件兜底 - 重播逻辑包一层
setTimeout(() => { /* 上述三步 */ }, 100) - 重播前清空可能冲突的内联样式:
el.style.transform = ''、el.style.opacity = '' -
animation-duration别小于0.15s(150ms),否则部分 Android Webview 会跳过首帧
最容易被忽略的是:reflow 这一步必须显式触发,且不能被 JS 引擎优化掉;还有就是动画类和初始状态类必须解耦,确保不可见时元素上完全没 animation 声明——任何残留都会干扰重播判定。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











