应使用 @supports (min-height: 100dvh) 包裹整条 min-height: 100dvh 规则,因 iOS 15 及更早版本不支持 dvh 会忽略该声明导致页面塌陷;100vh 在 Safari 中因地址栏高度计算偏差引发滚动条、内容裁切等问题,需用 min-height 而非 height 并配合兜底和 JS 动态 --vh 变量确保兼容性。

直接用 min-height: 100dvh 替代 100vh,但必须用 @supports (min-height: 100dvh) 包裹整条规则,否则 iOS 15 及更早系统会完全忽略该声明,元素高度回退为 auto,页面视觉上“塌陷”或留白。
为什么 100vh 在 iOS Safari 里会多出滚动条
它不是你 CSS 写错了,是 Safari 把地址栏高度算进去了:页面刚加载时地址栏挂着,window.innerHeight 可能是 762px,但 1vh 却按设备物理屏高(比如 812px)算成 8.12px,于是 100vh 实际是 812px——比你能看见的区域高约 50px。滚动后地址栏收起,视口变大,但 100vh 不重算,内容就被切掉、底部留白,甚至触发意外滚动条。
- 典型现象包括:
overflow: hidden失效、position: fixed元素错位、全屏轮播图顶部被遮挡 - Android Chrome 同样存在,尤其在 PWA 或全屏模式下更明显
-
height: 100%无效,除非html和body都显式设了height: 100%(它们默认是auto)
正确写法:@supports 必须包裹整条规则
错误写法是只包值,比如 min-height: 100vh; min-height: 100dvh;——新 Safari 仍用 100vh,根本没触发 dvh。也别裸写 height: 100dvh,它会强制裁剪内容,用户滑不到底部。
- 前置
min-height: 100vh作为兜底,确保老环境至少有基础高度 -
@supports (min-height: 100dvh)必须包裹整个选择器和声明块 - 优先用
min-height而非height:内容超长时不会被截断
.page {
min-height: 100vh;
}
@supports (min-height: 100dvh) {
.page {
min-height: 100dvh;
}
}绝对定位元素容易失效的坑
如果你给一个 position: absolute 元素写了 min-height: 100dvh,但它的父容器没设明确高度(比如只是 position: relative 且无 height),那它依然不会占满屏幕——dvh 依赖包含块,不是“强制撑满窗口”。
立即学习“前端免费学习笔记(深入)”;
- 确保父容器(如
body或直接祖先)有min-height: 100dvh或显式高度 - 对绝对定位元素,更稳妥的是用
top: 0; bottom: 0;替代height: 100dvh - 别信
-webkit-fill-available能一劳永逸:它只对height有效,min-height不认;不响应软键盘弹起;iPad Chrome 中甚至会叠加导致高度翻倍
兜底方案:JS 动态设 --vh 变量
当需要兼容 iOS 15 以下、微信 WebView 或某些不稳定 WebView 时,JS 是唯一能精确响应每次视口变化的路径。但时机和防抖不能错。
- 必须在
DOMContentLoaded后立即执行一次,否则首屏渲染用的是地址栏未收起时的错误初始值 - 监听
resize即可,orientationchange在部分 iOS 版本中不可靠 - 必须防抖:iOS 连续触发
resize,直接更新样式会导致重排抖动;用requestAnimationFrame最稳妥 - CSS 中写
min-height: calc(var(--vh, 1vh) * 100),其中1vh是兜底,避免 JS 未加载时整个元素缩成一条线 - 别忘了给
html和body设margin: 0和height: 100%,否则window.innerHeight可能被外边距干扰
真正麻烦的不是单位写错,而是混用 dvh 和 svh,或者在 position: fixed 元素上直接套 100dvh 却没设包含块高度——这些地方一错,fixed 元素就飘走,而且很难定位。


















