应改用 matchMedia 监听 orientation 变化并手动管理动画生命周期,因 resize 事件在 iOS Safari 等环境中不触发横竖屏切换,且无法反映真实方向变化;需 cancel 动画、requestAnimationFrame 延迟重置 class、显式清除 transform/opacity 等残留样式,并首次加载时手动执行 handleOrientation。

移动端横竖屏切换时 CSS 动画中断,不是动画“被暂停”,而是浏览器在方向变化后丢弃了原动画实例、重新计算并启动新动画——resize 事件本身不触发动画重置,但它常被误用作响应入口,结果反而加剧问题。
为什么监听 resize 无法真正解决动画中断
resize 事件在多数 iOS Safari 和部分 Android WebView 中根本不会触发横竖屏切换;即使触发,它也发生在布局重排之后,此时动画早已被样式引擎强制终止。更关键的是:resize 不区分方向,也无法反映视口真实宽高比变化,容易在折叠屏、分屏或地址栏显隐时误判。
- 仅靠
window.addEventListener('resize', ...)在真机上大概率收不到回调(尤其 iOS) - 即使收到,
event.target是window,但动画中断根源不在尺寸变化本身,而在媒体查询规则切换导致的animation属性全量重写 - 在
resize回调里直接element.classList.remove('animate')再add,会引发强制重排+重绘,动画更卡
正确做法:用 matchMedia 监听 orientation + 手动管理动画生命周期
必须放弃 resize,改用 window.matchMedia 主动监听方向状态,并在变更时主动取消、重置、再触发动画,而非依赖 CSS 自动覆盖。
- 初始化时获取当前状态:
const mql = window.matchMedia('(orientation: landscape)'); - 监听变更:
mql.addEventListener('change', e => { handleOrientation(e.matches); }); - 在
handleOrientation中先调用element.getAnimations().forEach(a => a.cancel())清理残留动画 - 用
requestAnimationFrame延迟一帧再添加新动画 class,避开同步样式冲突 - 避免在监听回调中读取
offsetTop、getComputedStyle等强制同步布局的属性
动画重置时容易忽略的 DOM 状态残留
即使取消了动画,元素的 transform、opacity 等最终值可能仍停留在动画结束帧,下一次动画从该值开始,造成“跳变”。这不是 bug,是 CSS 动画的自然行为。
- 手动重置关键样式:
element.style.transform = 'none'; element.style.opacity = ''; - 若需保留视觉连贯性,改用
transition+ JS 控制起止值,而非依赖animation关键帧 - 对 SVG 元素,注意
getAnimations()不返回 SMIL 动画,需单独处理<animate></animate>节点 - 使用
animation-fill-mode: forwards的元素,cancel()后样式不会自动回退,必须显式清除
最隐蔽的问题是:首次加载即横屏的页面,matchMedia 的 change 事件不会触发,必须手动执行一次 handleOrientation(mql.matches);否则动画永远按竖屏逻辑运行。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











