@media (orientation: landscape/portrait) 必须配合正确的 viewport 设置(含 width=device-width)才生效,否则完全不触发;它仅依宽高比判断、有 reflow 延迟,且易受地址栏、折叠屏等干扰,推荐用 window.matchMedia 监听并叠加 min-width 等条件增强可靠性。

@media (orientation: landscape) 和 @media (orientation: portrait) 是最直接的写法,但单独用它们大概率失效——关键不在媒体查询本身,而在 viewport 设置和触发时机。
viewport 标签写错,@media (orientation: landscape) 就压根不计算
iOS Safari 和 Android Chrome 都依赖 <meta name="viewport"> 才会真正响应方向变化。漏掉或写错,orientation 媒体查询就永远不匹配:
- 必须包含
width=device-width;缺它,横屏时浏览器仍按竖屏逻辑渲染 - 禁用
width=375这类固定值;视口宽度锁死,媒体查询无法重算 - 避免 JS 动态覆盖 viewport;初始设置后又被脚本改写,后续旋转就失效
推荐写法:<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
只靠 orientation 媒体查询,样式常延迟、漏掉或误判
它不是实时响应物理旋转,而是等浏览器完成重排(reflow)后才重新计算,通常有几十毫秒延迟。更麻烦的是:
立即学习“前端免费学习笔记(深入)”;
- 判定逻辑是
if (window.innerWidth > window.innerHeight) → landscape,和设备传感器无关 - iOS 15+ 快速旋转可能跳过触发;Android Chrome v79+ 后续旋转不再更新 orientation
- 横屏时地址栏未收起、折叠屏半展开,
window.innerHeight可能仍大于宽度,导致orientation: landscape不匹配
稳妥做法是叠加断点:@media (orientation: landscape) and (min-width: 768px) 或 @media (max-height: 480px) and (min-width: 640px) —— 后者直接响应真实瓶颈(高度骤减)。
JS 里别再用 window.orientation
这个 API 在 Chrome 99+ 已彻底移除,Safari 和 Firefox 也早标记为 deprecated。它只反映页面加载时的初始值,或某些旧安卓 WebView 的残余行为,不能代表真实方向:
- 正确方式是
window.matchMedia("(orientation: landscape)").matches - 监听变化必须用
mql.addEventListener("change", ...),不是resize -
resize在桌面端频繁触发,在移动端却不一定随旋转触发(尤其 iOS Safari)
初始化也要手动调用一次,否则首次加载状态可能没应用:handleOrientation();
100vh、100vw、flex-direction 这些值在横竖屏切换后最容易翻车
CSS 不会自动兜底,必须显式干预:
-
100vh在 iPhone 14 横屏下只剩 390px,内容被截;改用100dvh(动态视口高度),或降级为min-height: 100%+html, body { height: 100% } -
100vw在 iOS Safari 横屏时包含已隐藏地址栏高度,造成溢出;优先用100%或100dvw(注意 Android Chrome 100 以下不支持) -
flex-direction不会自动翻转;竖屏用column,横屏必须显式写row,否则子项仍堆叠
真机测试比模拟器可靠得多——Chrome DevTools 的 “Rotate” 按钮不等价于真实旋转,很多问题只在真机上暴露。


















