100vh 在 iOS Safari 中不等于屏幕高度,因其按初始视口计算且不随地址栏显隐更新,导致滚动时内容塌陷或截断;推荐优先使用 100dvh,兼容现代浏览器,旧版需 JS 监听 resize 动态修正。

为什么 100vh 在 iOS Safari 里不等于屏幕高度
因为 iOS Safari 的地址栏和底部工具栏会动态显示/隐藏,vh 单位在页面加载时按「初始视口」计算,后续滚动时并不更新。结果就是:页面刚打开看着满屏,一滚动就露白底,或者内容被截断。
- 只在移动端(尤其是 iOS)明显,Android Chrome 表现相对稳定
-
100vh实际值 ≈ 可视区域高度(不含地址栏),但 JS 读到的window.innerHeight却是变化的 - 用
min-height: 100vh无法解决——塌陷发生在「高度计算完成之后」
用 env(safe-area-inset-bottom) 补齐底部安全区
当页面需要贴底(比如 tabbar、固定 footer),光靠 100vh 会压到刘海或圆角下方,甚至被系统栏遮挡。这时候必须主动适配安全区。
- 仅适用于支持 CSS 环境变量的浏览器(iOS 11.2+、Chrome 69+)
- 写法:
height: calc(100vh - env(safe-area-inset-bottom)) - 注意:不能直接写
100vh+env()相加,要统一用calc()包裹 - 如果不需要适配刘海,但想防塌陷,可先加
viewport-fit=cover告诉 Safari 允许全屏渲染
用 100dvh 替代 100vh(推荐新方案)
dvh 是「动态视口单位」,浏览器会实时响应地址栏显隐,自动更新数值。相比 vh,它是目前最干净的解法。
- 兼容性:Chrome 105+、Safari 16.4+、Firefox 110+;旧版 Safari 需降级回
100vh - 写法直接替换:
height: 100dvh,无需 JS 或 calc - 不要混用:
min-height: 100dvh和height: 100dvh效果不同,后者更可靠 - 注意:部分 Android WebView(如微信内置)尚未支持,上线前务必真机测试
JS fallback:监听 resize 动态修正高度
当必须兼容老 iOS 或 WebView 时,得靠 JS 抓取真实可视高度,并写入内联样式或 CSS 变量。
立即学习“前端免费学习笔记(深入)”;
- 别用
orientationchange——它不触发地址栏显隐事件 - 监听
resize是唯一可行方式,虽然略滞后,但比不处理强 - 示例:
document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`);然后在 CSS 中用height: calc(var(--vh, 1vh) * 100) - 注意:首次加载时也要执行一次,否则白屏期就塌了
实际项目里,100dvh 能覆盖大多数现代场景,但只要目标用户含大量 iOS 15 以下设备,就必须准备 resize fallback。安全区补丁不是可选项——哪怕没刘海,某些 iPad 横屏下也会触发 env(safe-area-inset-bottom)。


















