应优先使用100dvh替代100vh,但必须用@supports (min-height: 100dvh)精确检测并外部声明min-height: 100vh兜底;错误写法会导致旧版Chrome或定制WebView完全忽略高度而塌陷。

Chrome 109+ 支持 dvh,但降级逻辑写错反而更糟
Chrome Android 109+ 和 Desktop 109+ 已原生支持 100dvh,但直接替换 100vh 或写错 @supports 包裹方式,会导致旧版 Chrome(如 105–108)和部分定制安卓 WebView(华为 EMUI、小米 HyperOS)完全忽略高度声明,页面塌成一条线。
关键错误示例:.page { min-height: 100vh; min-height: 100dvh; } —— 老 Chrome 会跳过第二行,但新 Chrome 不会覆盖第一行,结果仍是 100vh,问题照旧。@supports (height: 100dvh) { ... } —— height 不支持 dvh,该查询永远为假,整块规则被丢弃。
正确做法必须满足三点:
-
@supports必须用min-height: 100dvh或max-height: 100dvh精确匹配,不能省略属性名或换用height - 兜底声明(
min-height: 100vh)必须写在@supports外部,确保所有环境至少有基础高度 - 必须用
min-height,不是height;否则内容超长时会被截断,用户滑不到底部
标准写法:
立即学习“前端免费学习笔记(深入)”;
.page {
min-height: 100vh;
}
@supports (min-height: 100dvh) {
.page {
min-height: 100dvh;
}
}微信 X5 内核、QQ 浏览器等不支持 dvh,JS fallback 不能只监听 resize
微信内置浏览器(X5 内核)、QQ 浏览器、部分安卓定制系统(如 OPPO ColorOS 旧版)至今未启用 dvh,@supports 查询返回 false,必须 JS 回退。但只监听 window.resize 是无效的——它在软键盘弹出、地址栏收起时基本不触发。
真实生效的监听组合:
- 监听
visualviewport.resize:Chrome 和新版 WebView 支持,能捕获键盘/地址栏变化 - 监听
input和textarea的focusin(不是focus),并在回调里加setTimeout(() => {}, 0)延迟读取window.innerHeight,否则拿到的是键盘弹出前的旧值 - 监听
blur后加setTimeout(() => {}, 100)等键盘动画结束再恢复,否则页面闪一下 - 首次执行必须在
DOMContentLoaded后立刻运行,否则首屏渲染用的是地址栏未收起时的错误初始值
注意:华为 EMUI 某些版本的 visualViewport.height 会返回负数或 0,需校验:if (v.height > 0 && v.height 。
绝对定位元素用 100dvh 没反应?问题不在 dvh,而在包含块
position: absolute 元素的 100dvh 高度不会自动“占满屏幕”,它仍依赖包含块(containing block)的高度计算。常见于弹窗遮罩、固定按钮、全屏轮播容器。
典型失效场景:
- 父容器(如
body或直接祖先)没设min-height: 100dvh或显式高度 → 子元素100dvh实际算出来是0 - 对绝对定位元素写
height: 100dvh,不如改用top: 0; bottom: 0;更可靠(前提是父容器已有高度) - 父容器本身靠 CSS 变量(如
--vh)驱动,但变量初始化晚于子元素渲染,导致子元素读到的是1px初始值
修复建议:给最近的非 static 定位祖先加 min-height: 100dvh(并配 @supports 降级),或直接放弃 100dvh,用 top/bottom + min-height 组合。
svh/lvh 不是 dvh 的备选,混用会破坏布局一致性
看到 100svh 就以为是“更小的 100dvh”?这是最大误区。100svh 和 100lvh 是静态锚点值,不是动态响应单位:前者永远按地址栏**强制展开**时的高度算(最保守),后者永远按地址栏**强制收起**时的高度算(最激进)。
强行全局把 100vh 替换为 100svh,会导致地址栏收起后大量留白;全换 100lvh,又会让地址栏弹出时顶部内容被截断。它们都不能用于通用容器高度控制,也不能在 @media 中使用,JS 里也读不出像素值(getComputedStyle 返回字符串 "100svh")。
真正该用 svh 的地方极少:
- 支付页底部确认按钮:必须始终避开地址栏,用
bottom: clamp(1rem, 5svh, 2rem) - 启动页、广告页这类全屏沉浸场景:可考虑
100lvh,但要接受滚动初期顶部可能被遮挡
绝大多数普通容器(轮播图、主内容区、登录页)应坚持用 100dvh + @supports 降级,别试图用 svh/lvh “微调”。


















