必须设置 width=device-width,否则 @media (orientation: landscape) 几乎不触发;其根源在于 viewport 缺失该属性导致浏览器无法识别方向变化,且需配合尺寸断点与 matchMedia 才可靠。
width=device-width,@media (orientation: landscape) 就不会触发几乎所有横屏样式不生效的问题,根源都在 <meta name="viewport"> 标签写错了。iOS Safari 和 Android Chrome 都靠它识别方向变化,漏掉 width=device-width,浏览器压根不知道你转了屏,@media (orientation: landscape) 也就永远不匹配。
常见错误包括:
width=375 或 width=768 这类固定值——视口宽度锁死,旋转后逻辑宽高比不变,媒体查询无依据更新user-scalable=yes,双击缩放干扰重排,间接导致 orientation 判断延迟或跳过必须用这行(且确保它在 <head> 中最早位置):
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
@media (orientation: landscape) 不是实时响应,得配合尺寸断点才稳orientation 媒体查询不是一转屏就立刻生效,而是在浏览器完成重排(reflow)后才重新计算,通常有几十毫秒延迟。更麻烦的是:它只看“逻辑宽度是否大于高度”,不关心物理朝向、地址栏是否收起、键盘是否弹出——这些都会让判断失准。
真机上典型失效场景:
window.innerHeight > window.innerWidth,orientation: landscape 根本不匹配稳妥做法是组合判断:
@media (orientation: landscape) and (min-aspect-ratio: 13/9) —— 13:9 ≈ 1.44,覆盖多数横屏设备实际宽高比@media (max-height: 480px) and (min-width: 640px) —— 直接响应高度骤减这个真实瓶颈,兼容性更好@media (orientation: landscape) 控制关键布局,比如全屏容器或导航结构100vh、flex-direction、vw 单位容易翻车方向切换后 CSS 基准突变,但不会自动兜底。几个高频翻车点:
100vh 在 iPhone 14 横屏下只剩约 390px,内容常被截断;优先改用 100dvh(动态视口高度),Android Chrome 100 以下不支持时降级为 min-height: 100% + html, body { height: 100% }
flex-direction: column 竖屏正常,横屏不会自动变成 row;必须显式写 @media (orientation: landscape) { .container { flex-direction: row; } }
font-size: 4vw 横屏时暴增(竖屏 100vw≈375px,横屏≈812px),推荐用 clamp(14px, 2.5vw, 16px) 锁死区间100vw 在 iOS Safari 横屏时包含已隐藏地址栏高度,造成水平溢出;优先用 100% 或 100dvw
orientationchange 事件,改用 window.matchMedia
window.addEventListener('orientationchange', ...) 已在 iOS 12+ 和所有现代安卓浏览器中废弃。它只读陀螺仪角度,和实际 CSS 渲染方向脱节——比如平板横放但 WebView 强制竖屏,事件照发,但 @media 完全不匹配。
正确做法是主动查询并监听:
const mql = window.matchMedia('(orientation: landscape)');if (mql.matches) {
// 初始化横屏状态,比如加 class 或触发 JS 逻辑
}
mql.addEventListener('change', e => {
if (e.matches) {
// 进入横屏
} else {
// 退出横屏
}
});
注意:首次加载必须手动检查 mql.matches,否则首屏可能错位;监听器要存引用,方便销毁(比如组件卸载时)。
横竖屏适配真正的难点不在写多少媒体查询,而在理解浏览器怎么算“横屏”——它不看你手机怎么拿,只看你 innerWidth 和 innerHeight 的数值关系,以及 viewport 是否允许它重新计算这个关系。漏掉 width=device-width 或只依赖 orientation,等于把判断权交给了一个不可靠的中间层。