@media (orientation: portrait/landscape) 单独使用大概率失效,因依赖 viewport 中 width=device-width 才触发方向重算,且仅基于宽高比判断(innerWidth > innerHeight),不读传感器;推荐用 window.matchMedia 监听 change 事件并组合 min-width 或宽高比条件增强稳定性。

@media (orientation: portrait) 和 @media (orientation: landscape) 是最直接的检测方式,但单独用它们大概率不生效——问题不在 CSS 写法,而在 viewport 设置、触发时机和判定逻辑本身。
viewport 缺失 width=device-width 就完全不触发
iOS Safari 和 Android Chrome 都依赖 <meta name="viewport" content="width=device-width, ..."> 才会启用方向重算。漏掉它,浏览器压根不比较 window.innerWidth 与 window.innerHeight,媒体查询永远不匹配。
- 写死
width=375或其他固定值 → 视口宽度被锁死,旋转后innerWidth不变,orientation永远不会更新 - JS 动态覆盖初始
<meta>→ 初始设置生效后又被改写,后续旋转失效 - 推荐写法:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
window.matchMedia 是唯一可靠的 JS 检测方式
window.orientation 已废弃(Chrome 99+ 彻底移除,Safari/Firefox 早就不响应),resize 事件在移动端不保证随旋转触发。真正该用的是 matchMedia + change 回调:
- 首次加载必须主动检查:
window.matchMedia("(orientation: portrait)").matches,不能只等 change - 监听变更必须用
mql.addEventListener("change", ...),不是orientationchange(已废弃) - IE11 兜底用
mql.addListener(),但实际影响极小(IE11 无自动旋转逻辑) - 判定逻辑是
if (window.innerWidth > window.innerHeight) → landscape,和物理传感器无关
@media (orientation: ...) 常见失效场景
它只看视口宽高比,不是设备朝向,所以这些情况会导致误判或不触发:
立即学习“前端免费学习笔记(深入)”;
- iOS Safari 横屏时地址栏未收起 →
innerHeight变大,innerWidth > innerHeight不成立,landscape不匹配 - 用户放大页面到很大 → 竖着拿手机但
innerWidth > innerHeight,反而触发横屏样式 - iOS 15+ 快速旋转可能跳过 reflow,Android Chrome v79+ 后续旋转不再更新状态
- 桌面开发者工具点 “Rotate” 图标才模拟真实旋转;单纯拉宽窗口不会触发
orientation
稳妥做法:叠加断点,别单靠 orientation
纯 orientation 太脆弱,业务强依赖方向时必须组合条件:
-
@media (orientation: landscape) and (min-width: 480px)—— 过滤掉窄屏横置(如手机横拍) -
@media (max-height: 480px) and (min-width: 640px)—— 直接响应高度骤减这个更稳定瓶颈 -
@media (orientation: landscape) and (min-aspect-ratio: 1280/720)—— 用宽高比代替绝对尺寸,兼容折叠屏 - 横屏下慎用
100vh/100vw,优先用100dvh/100dvw(iOS Safari 横屏下100vh常被截断)
真正难的不是写对媒体查询,而是理解它只是一张宽高比快照——它不关心你手机是横着拿还是竖着拿,只关心此刻视口里哪个数字更大。所有“为什么没生效”的问题,几乎都卡在 viewport、reflow 延迟、或把 orientation 当成了物理传感器。


















