根本解决方式是避免用媒体查询干预正在运行的动画,而应将动画逻辑与方向适配解耦:媒体查询仅控制容器布局(如尺寸、transform-origin),动画由JS或class统一触发;必要时用matchMedia监听并手动管理动画生命周期。

CSS 动画在横屏切换时重置,不是动画本身被“打断”,而是媒体查询触发新样式规则,覆盖了原有动画状态(如 animation-play-state、animation-delay 或关键帧进度)——根本解决方式不是强行“保持状态”,而是避免用媒体查询去干预正在运行的动画。
为什么 @media (orientation: landscape) 会让动画突然跳回起点
常见错误是:在竖屏下写 .box { animation: slideIn 0.3s; },横屏时又用 @media (orientation: landscape) { .box { animation: rotateIn 0.4s; } }。这会导致浏览器丢弃原动画、新建一个,视觉上就是“重置”。
- 浏览器不保留跨媒体查询的动画上下文,
animation属性全量替换,相当于重新声明 - 即使两个动画名相同,只要
animation-duration、animation-timing-function或关键帧定义有微小差异,也会被当作新动画处理 - 某些安卓 WebView 在方向切换瞬间会强制重绘整个 layer,动画帧直接丢失
真正能“保持动画状态”的做法:只用 media 查询控制容器,不动动画本身
把动画逻辑和方向适配解耦。动画由 JS 控制启停或由 class 触发,媒体查询只负责调整布局容器尺寸、定位或 transform-origin 等不影响动画播放的属性。
- 动画统一用
class="is-animating"触发,不依赖媒体查询中的animation声明 - 横竖屏只改
.container的width/height、transform-origin或padding,让动画元素自然适应新空间 - 需要旋转容器时,用
transform: rotate(90deg)+transform-origin: top left,而非靠动画关键帧硬转 - 若必须换动画效果(如横屏时加缩放),用 JS 监听
matchMedia变更后,手动调用element.getAnimations().forEach(a => a.cancel())再element.classList.add("new-animation"),比 CSS 覆盖更可控
容易被忽略的兼容性陷阱
横屏动画“看似正常”但在真机上失效,往往卡在这几个点:
-
100vh/100vw在 iOS Safari 横屏时仍按竖屏视口计算,导致动画位移目标错乱;改用100dvh/100dvw(需检查浏览器支持)或 JS 动态读取window.innerHeight - 部分 Android Chrome 不触发
resize,但matchMedia('(orientation: landscape)')的change事件可靠——别混用两种监听 - 动画中用了
position: fixed,横屏后固定锚点偏移,视觉上像“重置”,其实是定位基准变了;优先改用position: absolute配合父容器transform - CSS 关键帧里写了
top: 50%; transform: translateY(-50%)这类依赖视口尺寸的值,横屏后50%含义已变,应改用calc()或 JS 补偿
最稳妥的路径是:动画逻辑收口到 JS,媒体查询只管布局容器;横竖屏切换本质是“换画布”,不是“换动画”。强行让 CSS 动画跨 orientation 持续,等于在对抗浏览器渲染机制。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











