最轻量解法是用 @supports (min-height: 100dvh) { .page { min-height: 100dvh; } } 包裹整条规则,并在外层保留 min-height: 100vh 降级;对绝对定位元素应改用 top: 0; bottom: 0;iOS 15/微信 X5 需 JS 动态设 --vh 并监听 scroll 和 weixinjsbridgeReady,首次执行须在 DOMContentLoaded 后且用 requestAnimationFrame 防抖。

直接用 min-height: 100dvh 替代 100vh 是最轻量、最有效的解法,但必须配合 @supports 降级,否则 iOS 15 及微信 X5 内核会完全塌陷。
为什么 100dvh 必须用 @supports 包裹整条规则
旧版 Safari(iOS 15.x 及更早)、微信安卓 X5 内核等环境根本不识别 dvh 单位,遇到不认识的值会跳过整条声明。如果你只写:
.page {
min-height: 100vh;
min-height: 100dvh;
}老环境忽略第二行,新环境仍走第一行——问题照旧。正确写法是:
-
@supports必须包裹整个选择器和声明块,不能只包值 - 兜底的
min-height: 100vh必须写在@supports外层,确保所有浏览器至少有基础高度 - 构建工具(如 PostCSS)若自动把
dvh降级成vh,必须关掉该功能
position: absolute 元素设了 100dvh 为啥没撑开
百分比高度(包括 100dvh)依赖包含块(containing block)的高度,不是“强制占满屏幕”。常见于遮罩层、弹窗、底部按钮。
立即学习“前端免费学习笔记(深入)”;
- 父容器(如
body或直接祖先)没设min-height: 100dvh→ 子元素计算出的高度为 0 - 别对绝对定位元素用
height: 100dvh,改用更可靠的top: 0; bottom: 0; - 若父容器本身也靠
--vh驱动,需确保它先完成初始化,否则子元素读到的是初始1px
需要兼容 iOS 15 或微信 WebView?JS 动态设 --vh 是唯一解
这些环境完全不认 dvh 或 svh,CSS 方案彻底失效。必须用 JS 动态读取 window.innerHeight 并注入 CSS 变量:
- 必须在
DOMContentLoaded后立即执行一次,否则首屏渲染用的是地址栏未收起时的错误初始值 - 监听目标不只是
resize:iOS 地址栏收起只触发scroll,微信还要监听weixinjsbridgeReady - 防抖必须用
requestAnimationFrame,setTimeout在微信安卓下极易卡死 - CSS 中统一用
min-height: calc(var(--vh, 1px) * 100),不依赖父容器是否设了height: 100%
真正容易被忽略的是:即使用了 100dvh,也要检查父容器是否参与高度继承链;而一旦引入 JS 方案,requestAnimationFrame 防抖和首次同步执行这两个点,漏掉任何一个都会导致首屏白屏或滚动跳变。


















