100vh 固定于初始视口高度,不响应地址栏/键盘变化;box-sizing: content-box 下 padding/border 会额外增加高度;应使用 min-height: 100dvh 配合 @supports 降级,并控制 flex-shrink 和 overflow-y。

100vh 基于布局视口,不是你看到的那块屏幕
它算的是包含地址栏、底部导航栏在内的“理论最大高度”,而用户滚动或键盘弹出时,真正能操作的视觉区域(visual viewport)会实时变化。但 100vh 的像素值在页面加载那一刻就冻结了,后续工具栏收起 → 实际可视区变大,100vh 却没变 → 元素撑不满;键盘弹出 → 可视区变小,100vh 还是那个大值 → 内容被顶出或底部留白。
盒模型叠加让溢出更隐蔽
默认 box-sizing: content-box 下,min-height: 100vh 只管内容区高度,padding 和 border 会额外加高。比如:
.modal {
min-height: 100vh;
padding: 24px;
}
实际总高度 = 100vh + 48px,哪怕视口刚好 800px,它也变成 848px,必然触发滚动条。这不是 bug,是盒模型按规范执行的结果。
别直接用 height: 100dvh,这是常见误操作
100dvh 是动态单位,但它只适合做最小约束,不是强制占满:
立即学习“前端免费学习笔记(深入)”;
- ❌
height: 100dvh:内容超长时会被硬裁剪,用户滑不到底部表单或按钮 - ✅
min-height: 100dvh+max-height: 100dvh+overflow-y: auto:既响应键盘/滚动,又保内容可访问 - ⚠️ 父容器必须有明确高度上下文,否则 flex 容器里
min-height: 100dvh可能不生效
@supports 不是可选项,是保命线
iOS 15、微信 X5 内核等旧环境遇到 100dvh 会直接忽略整条声明,导致弹窗塌陷为 0 高度。降级必须写在 @supports 外层:
.dialog {
min-height: 100vh;
}
@supports (min-height: 100dvh) {
.dialog {
min-height: 100dvh;
}
}
别写成 min-height: 100vh; min-height: 100dvh —— 老浏览器解析到第一个就停,第二个压根不读。
真正难处理的不是单位本身,而是当 100dvh 生效后,flex 子项仍可能被压缩——比如键盘弹起时输入框被顶走,这需要单独控制 flex-shrink: 0 和 overflow-y 分层约束。


















