应使用 min-height: 100vh 作为兜底,配合 @supports (min-height: 100dvh) { min-height: 100dvh; } 增强,并在不支持 dvh 的环境(如微信、iOS 15)中通过监听 visualViewport.resize 或 scroll 动态设置 CSS 变量 --vh 实现兼容。

直接用 100dvh 替代 100vh,但必须搭配 min-height 和降级声明,否则在旧环境会塌陷或截断内容。
为什么 100vh 在移动端滚动时会跳变
100vh 是基于页面加载瞬间的视口高度计算的静态值,而 iOS Safari 和 Android Chrome 的地址栏/底部工具栏会在滚动时收起或展开,导致 window.innerHeight 实时变化。CSS 不重算 100vh,结果就是全屏容器高度“卡死”,内容视觉上突然上移或下压。
- 典型现象:轮播图顶部被截、遮罩层盖不住底部、
position: fixed元素错位 - 它不是 bug,是 CSS 规范早期对“viewport”定义未覆盖动态工具栏场景所致
-
100svh和100lvh也不是解——它们是两个固定锚点值,不响应滚动,强行替换只会让留白或裁切更明显
正确写法:min-height + dvh + fallback
不要写 height: 100vh; height: 100dvh;,也不要用逗号分隔单位(CSS 不支持)。优先用 min-height,避免内容超长时被强制裁剪。
- 基础兜底:
min-height: 100vh; - 现代浏览器增强:
@supports (min-height: 100dvh) { min-height: 100dvh; } - 禁止写
height: 100dvh—— 它会把内容撑满且不可滚动,用户滑不到下面 - 构建工具(如 PostCSS)若自动把
dvh降级为vh,必须关掉该功能,否则白忙一场
微信和 iOS 15 等不支持 dvh 的环境怎么兜底
微信内置浏览器(X5 内核)、iOS 15.x、部分安卓 WebView 根本不识别 dvh,CSS 方案在此类场景完全失效。JS 是唯一可靠路径,但监听目标不能是 resize —— iOS 地址栏收起时不触发 resize,只触发 scroll。
立即学习“前端免费学习笔记(深入)”;
- 必须监听
visualViewport?.resize(iOS 最准)或scroll+resize+orientationchange - 首次执行要同步运行,在
DOMContentLoaded前或刚进脚本就调用,否则首屏白屏期高度就错 - 设 CSS 变量:
document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`) - CSS 中统一用:
min-height: calc(var(--vh, 1px) * 100);,不依赖父级height: 100%
容易被忽略的关键点
100dvh 解决的是“值更新”,但不保证重排时机。如果父容器没有触发 layout(比如 display: contents 或某些 Flex 场景),子元素即使写了 100dvh 也可能卡住不动。另外,getComputedStyle(el).height 返回的是字符串 "100dvh",无法用于 JS 计算;@media (min-height: 100dvh) 语法非法,别试。


















