根本原因是视口单位和布局属性不会随横竖屏自动更新:100vh/100vw基准突变导致截断或溢出,flex-direction等不自动翻转,orientation媒体查询依赖重排且易受地址栏、键盘干扰,所有问题前提都是viewport缺失width=device-width。

根本原因不是 CSS 写错了,而是浏览器在方向切换时没有重新计算关键布局参数——vh、vw、flex-direction、position: fixed 这些值不会自动“翻转”,它们只是按当前视口尺寸静态计算一次,而横竖屏切换后,这个“当前”已经变了。
为什么 100vh 和 100vw 在横屏下突然失效
这两个单位在旋转后基准突变,但 CSS 不会主动修正渲染结果:
-
100vh在 iPhone 14 横屏时变成约 390px(不是原始 844px),内容直接被截断;它依据的是 layout viewport 高度,而横屏时地址栏收起/弹出会改变该值,但浏览器不触发重排 -
100vw在 iOS Safari 横屏下仍包含已隐藏的地址栏高度,导致实际可渲染宽度变小,元素溢出并触发横向滚动条——这就是抖动和错位的源头 - Android Chrome 100 以下不支持
100dvh/100dvw,盲目替换会降级失败;真机测试必须覆盖 Safari + 微信 X5 + Chrome 95~105
@media (orientation: landscape) 为什么经常不触发或延迟生效
这个媒体查询不是实时监听陀螺仪,而是依赖浏览器完成一次 layout 重排后才比对逻辑宽高关系,因此极易漏判:
- iOS 15+ 快速旋转可能跳过触发;部分安卓 WebView(如微信 X5)压根不实现
screen.orientation,orientation媒体查询形同虚设 - 折叠屏半展开、虚拟键盘弹出时,
window.innerWidth > window.innerHeight为真,但设备并非真正横屏,纯靠 orientation 会误判 - 首次加载页面时,如果没手动检查
window.matchMedia("(orientation: landscape)").matches,初始横屏状态就直接丢失
Flex/Grid 布局为什么横屏后“看起来没变”
容器尺寸变了,但子项的排列逻辑没重置,所谓“自适应”只是错觉:
-
flex-direction: column不会自动变成row,必须在@media (orientation: landscape)中显式重写 -
grid-template-columns: repeat(3, 1fr)横屏后依然只分 3 列,但每列变宽,可能撑破卡片内边距;应改用repeat(auto-fit, minmax(200px, 1fr))) - iOS Safari 对
grid-auto-flow: column有渲染延迟,加transform: translateZ(0)可强制 GPU 加速,避免闪动
position: fixed 元素在横屏后跑偏的根本原因
不是定位写错了,而是 visual viewport 和 layout viewport 在旋转过程中不同步:
- 横屏瞬间,浏览器先用旧视口定位
top: 20px,再重绘新尺寸,造成“闪一下” - 绝对数值(如
top: 20px)无法响应 safe area 动态变化;应改用top: env(safe-area-inset-top) + calc(20px) - 若 fixed 元素设了
width: 100vw,同样面临溢出问题;必须搭配overflow-x: hidden和父容器width: 100%
最易被忽略的一点:所有这些表现都依赖正确的 <meta name="viewport">。漏掉 width=device-width,整个 orientation 媒体查询链就从根上失效——这不是兼容性问题,是基础前提没满足。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











