viewport标签必须含width=device-width,否则@media(orientation:landscape)不触发;它依赖重排延迟生效且仅按逻辑宽高比判断,需结合min-aspect-ratio或max-height等条件增强可靠性。

viewport 标签写错,@media (orientation: landscape) 就不会触发
这不是 CSS 写错了,而是浏览器压根不进方向重算流程。iOS Safari 和 Android Chrome 都依赖 <meta name="viewport"> 中的 width=device-width 来识别视口是否随旋转变化。
常见错误包括:
- 漏掉
width=device-width—— 缺它,横屏时浏览器仍按竖屏逻辑渲染,orientation永远不匹配 - 用了固定值如
width=375—— 视口宽度被锁死,旋转后window.innerWidth不变,媒体查询无从重算 - 被 JS 动态覆盖 —— 初始设置后又被脚本改写,后续方向变化失效
推荐写法:<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
@media (orientation: landscape) 单独用基本不可靠
它只看 window.innerWidth > window.innerHeight 这个宽高比结果,和手机物理朝向无关。这意味着:
立即学习“前端免费学习笔记(深入)”;
- 地址栏没隐藏时,
innerHeight变大,orientation: landscape可能根本不匹配(尤其 iOS Safari) - 用户把页面 zoom 很大,竖着拿手机但
innerWidth > innerHeight,照样触发横屏样式 - 折叠屏半展开、分屏模式下,判定容易误判
更稳妥的做法是组合判断:
@media (orientation: landscape) and (min-aspect-ratio: 1280/720)-
@media (max-height: 480px) and (min-width: 640px)—— 后者直接响应真实瓶颈(高度骤减)
横屏下 100vh、flex-direction 不会自动翻转
CSS 不会因为屏幕旋转就帮你把 flex-direction: column 切成 row。同样,100vh 在 iPhone 14 横屏下只剩 390px,常导致内容被截;100vw 在 iOS Safari 横屏时包含已隐藏地址栏高度,造成溢出。
必须显式干预:
- 改用
100dvh(动态视口高度),或降级为min-height: 100%+html, body { height: 100% } - 竖屏用
flex-direction: column,横屏必须显式写flex-direction: row -
font-size: 4vw横屏暴增;改用clamp(14px, 2.5vw, 16px)锁死区间
别用 orientationchange,改用 window.matchMedia
window.addEventListener('orientationchange', ...) 在 iOS 12+ 和所有现代安卓浏览器中已被废弃。它只反映设备陀螺仪角度,和实际 CSS 渲染方向脱节——比如平板横放但应用强制竖屏,事件照发,但媒体查询根本不匹配。
正确做法是:
- 用
window.matchMedia('(orientation: landscape)')主动查询 - 监听变更:
mql.addEventListener('change', e => { if (e.matches) { /* 横屏逻辑 */ } }) - 首次加载也要手动检查:
if (mql.matches) { /* 初始化横屏状态 */ }
真正难处理的不是“怎么写”,而是“怎么确保每次旋转都稳定响应”:地址栏收起时机、折叠屏中间态、快速旋转跳帧、WebView 行为差异……这些细节在真机上才暴露得最彻底。


















