最简解法是用100dvh替代100vh,现代浏览器已原生支持,无需JS监听;但需用@supports包裹并兜底min-height:100vh,禁用height:100dvh以防截断,慎用100svh,旧环境须JS动态fallback。

直接用 100dvh 替代 100vh 是最简解法
现代浏览器(iOS Safari 16.4+、Chrome 109+、Firefox 117+)已原生支持 dvh,它代表“当前实际可视区域高度”,会随地址栏收起/展开实时更新。不用 JS,不监听事件,一行 CSS 就能解决滚动时内容被遮挡或留白的问题。
但必须加兜底:
-
min-height: 100vh写在@supports外层,确保老设备至少有基础高度 -
@supports (min-height: 100dvh)包裹升级声明,避免不支持时整条规则被忽略 - 别用
height: 100dvh—— 内容超长会被截断;min-height更安全
100svh 不是 100vh 的替代品,慎用
100svh 表示“地址栏和底部工具栏都完全展开时的最小可视高度”,是个固定值,不响应滚动变化。在 iOS Safari 中,用户一滚动地址栏收起,100svh 还卡在最小高度上,反而导致容器偏矮、内容悬空、底部大片留白。
它只适合极少数场景:
立即学习“前端免费学习笔记(深入)”;
规划您的迪拜之旅 — 哈利法塔观景、沙漠探险、迪拜购物中心购物、棕榈岛度假村及黄金市场砍价。还提供支持...
- 固定定位的支付按钮、输入框等必须“永远避开工具栏”的元素
- 此时更推荐用
padding-bottom: env(safe-area-inset-bottom)+ 显式高度,而非依赖svh - Safari 直到 v17.4 仍不支持
svh,写了等于没写
旧版 iOS 和微信 X5 内核必须用 JS 动态 fallback
iOS 15 及更早、微信安卓(X5 v6.x)、部分低端 Android 浏览器根本不识别 dvh,且 window.innerHeight 在这些环境里也常不准(比如微信里 scroll 时不触发 resize)。不能只监听 resize。
关键动作要齐备:
- 在
DOMContentLoaded后立即执行一次,防白屏 - 监听
resize(横竖屏)、scroll(iOS 地址栏收起仅触发 scroll)、weixinjsbridgeReady(微信专属就绪事件) - 用
requestAnimationFrame节流更新--vh,避免安卓微信下高度卡死 - CSS 中写
height: calc(var(--vh, 1vh) * 100),1vh是降级兜底,不是随便写的
绝对定位容器用 dvh 前先检查包含块高度
position: absolute 元素的百分比高度(包括 100dvh)依赖于包含块高度。如果父容器没设 height,即使写了 100dvh,也可能失效——因为包含块高度为 auto,百分比计算无依据。
两种更稳的处理方式:
- 给最近的
position: relative祖先加height: 100%,并确保html、body有显式高度(如height: 100%) - 干脆绕过高度计算:对绝对定位元素用
top: 0; bottom: 0;,再配合padding-bottom: env(safe-area-inset-bottom)避开小黑条
真正麻烦的从来不是写对 100dvh,而是确认它在哪生效、在哪被忽略、以及被忽略时 JS 是否真能补上——尤其在微信和旧版 iOS 上,resize 事件可能压根不触发,得靠 scroll + setTimeout 组合试探。别信“监听 resize 就够了”这种简化说法。

















