100dvh不能直接用于height,因height强制固定高度会截断超长内容,必须用min-height: 100dvh保证至少一屏高且内容可自然延展;需@supports检测并降级至min-height: 100vh,且作用于主容器而非html/body。

100dvh 为什么不能直接写在 height 上
直接写 height: 100dvh 会导致内容超长时被截断,用户无法滚动查看完整内容。这不是浏览器 bug,而是 height 的语义决定的:它强制固定高度,不随内容伸缩。min-height: 100dvh 才是正确起点——它保证至少占满当前可见视口,内容多时自然撑高。
常见错误现象:
全屏轮播图底部突然留白、表单提交按钮被软键盘顶出可视区、页面首屏加载后一滚动就“跳一下”。这些都不是 JS 没跑或样式没加载,而是 height 锁死了容器上限。
- 必须用
min-height,不是height - 不要对
html或body直接设min-height: 100dvh—— 部分安卓 WebView 会忽略,作用于主容器(如.app、#root)更稳 - 若父容器是
position: fixed或absolute,100dvh仍依赖其包含块高度,此时需额外处理
@supports 必须包裹整条规则,不是只包值
写成这样是错的:.page { min-height: 100vh; min-height: 100dvh; }
旧版 Safari(iOS 15.x 及微信 X5 内核)会跳过第二行,但保留第一行,结果还是 100vh 的老问题;新版 Safari 则可能因解析顺序导致未生效。
正确结构是把整个规则块放进 @supports,且降级声明必须写在外面:
立即学习“前端免费学习笔记(深入)”;
.page {
min-height: 100vh;
}
@supports (min-height: 100dvh) {
.page {
min-height: 100dvh;
}
}-
@supports检测的是属性+值的组合是否被支持,不是单看单位 - Firefox 当前(2026 年中)仍不支持
dvh,所以降级是必须项,不是可选项 - 别在同一个选择器里混用
100dvh和100svh,Android 和 iOS 行为差异会导致 fixed 元素错位
position: absolute 元素用 100dvh 没反应?检查包含块
100dvh 对绝对定位元素无效,不是单位失效,而是 CSS 百分比高度(包括 100dvh)依赖包含块(containing block)有明确高度。如果父容器没设高度,100dvh 计算结果就是 0px。
典型场景:全屏遮罩层、弹窗、底部固定按钮。别指望 100dvh “自动撑满屏幕”。
- 优先改用
top: 0; bottom: 0;替代height: 100dvh,更可靠且无需父容器设高 - 若必须用
100dvh,确保父容器已设min-height: 100dvh(且该父容器本身也满足包含块条件) - 避免父容器靠
--vh变量驱动却未初始化完成——子元素读到的可能是初始1px
iOS 15 及微信旧版必须用 JS 回退 --vh
当用户群含大量 iOS 15.x 或微信 v8.0.48 及以下版本时,@supports (min-height: 100dvh) 会直接 fallback 到 100vh,而这些环境里的 100vh 仍按初始 layout viewport 计算,页面大概率塌成一条线。
JS 方案核心是动态读取 window.innerHeight 并注入 CSS 变量,但关键细节常被忽略:
- 首次执行必须在
DOMContentLoaded后立刻运行,否则首屏渲染用的是地址栏未收起时的错误高度 - 监听事件不能只用
resize:iOS 地址栏收起只触发scroll,微信需监听weixinjsbridgeReady,横竖屏要加orientationchange - 防抖必须用
requestAnimationFrame,setTimeout在微信安卓下易卡死 - CSS 中统一写
min-height: calc(var(--vh, 1px) * 100),不依赖祖先链是否设了height: 100%
真正容易被忽略的点:即使 100dvh 已支持,env(safe-area-inset-bottom) 仍需手动加在固定底部元素上——它不参与视口高度计算,只用于留白避让 iPhone 小白条或安卓手势区。


















