100dvh是解决移动端vh不准问题的正确方案,它能动态响应地址栏收起/展开,Chrome 100+和Safari 16.4+已支持,但需检查兼容性并设置100vh回退。

vh单位在移动端经常“不准”,因为地址栏会动态遮挡视口
很多开发者发现写 height: 100vh 在 iOS Safari 或 Android Chrome 里,页面底部被截断或留白——不是 CSS 写错了,是浏览器把地址栏算进 vh,但滚动时地址栏收起/展开,vh 却不重算。
真正稳定的方案不是只靠 vh,而是用 env() 配合 vh 回退:
-
height: 100vh作为基础 fallback(老浏览器兜底) -
height: calc(100vh - env(safe-area-inset-bottom))用于 iOS,但注意它只解决底部安全区,不解决地址栏问题 - 更关键的是:用
min-height: 100dvh替代100vh——dvh(dynamic viewport height)才是专为这种场景设计的单位,Chrome 100+、Safari 16.4+ 已支持
用 100dvh 前必须检查兼容性并设降级
dvh 确实能响应地址栏变化,但它在旧版 Safari(
稳妥写法是用 @supports 检测:
立即学习“前端免费学习笔记(深入)”;
section {
min-height: 100vh;
}
@supports (min-height: 100dvh) {
section {
min-height: 100dvh;
}
}别漏掉 min-height 而非 height:防止内容超长时被截断;也别只写 100dvh 不设 fallback,否则不支持的浏览器会失去高度控制。
媒体查询按视口高度做适配意义不大
用 @media (max-height: 600px) 这类规则去“针对小屏调布局”,实际效果很弱——因为:
- 同一设备横竖屏切换时
height值剧烈变化,但用户并不希望布局突变 - 不同机型的“600px”物理意义完全不同(比如 iPhone 14 Pro 的 600px 是 85% 屏幕,而低端安卓可能才 50%)
- 地址栏存在与否会让
height查询结果失真,和vh一样不可靠
真要响应高度变化,优先用 100dvh + flex/grid 自适应,其次考虑 JS 监听 resize 并读取 window.innerHeight(注意防抖),而不是依赖 CSS 媒体查询。
全屏滚动组件里 vh 错位,本质是滚动上下文错乱
像 Swiper、fullpage.js 这类库默认把每个 section 设为 height: 100vh,但在 iOS 上一滚动就错位——不是单位问题,是这些库在初始化时读了一次 window.innerHeight 就缓存了,后续地址栏隐藏后没更新。
修复思路很直接:
- 禁用库的自动高度计算(查文档找类似
autoHeight: false的配置) - 改用 CSS:
.section { height: 100dvh; },让浏览器原生接管 - 如果必须用 JS 控制,监听
resize后手动触发swiper.updateAutoHeight()或等效方法
复杂点在于:有些 WebView 不触发 resize,得加个定时器轮询 innerHeight 变化,但这是下策,优先走 CSS dvh。










