100vh在iOS Safari中撑出滚动条,是因为其按设备物理屏高(如812px)计算1vh,而非当前可见视口(如762px),导致100vh实际为812px,超出可视区域约50px;滚动后地址栏收起,但100vh不更新,引发裁切、留白或滚动条。

为什么100vh在Safari里会撑出滚动条
不是你写错了,是 Safari(尤其是 iOS 15 及更早、macOS Monterey 及之前)把地址栏高度算进了 100vh。页面刚加载时地址栏挂着,window.innerHeight 是 762px,但 1vh 却按设备物理屏高(比如 812px)计算为 8.12px,于是 100vh 实际被解析成 812px——比你能看见的区域高约 50px。滚动后地址栏收起,视口变大,但 100vh 值不更新,内容就被裁切、底部留白,甚至触发横向或纵向滚动条。
@supports (min-height: 100dvh) 必须包裹整条规则
裸写 min-height: 100dvh 或只包值是危险操作:iOS 15.x 及旧 WebView 直接忽略该声明,元素高度回退为 auto,页面视觉上“塌陷”成一条线。
-
@supports检测的是浏览器是否支持该 CSS 声明,不是某个值;必须包裹整个选择器块 - 外层先写兜底:
.page { min-height: 100vh; } - 再用
@supports替换:@supports (min-height: 100dvh) { .page { min-height: 100dvh; } } - 别写成
min-height: 100vh; min-height: 100dvh;—— 新 Safari 仍走100vh,根本没触发dvh
绝对定位元素设了 100dvh 为啥没反应
100dvh 不是“强制占满屏幕”,它依赖包含块(containing block)的高度。常见于弹窗、遮罩层、固定底部按钮等场景。
- 父容器(如
body或直接祖先)没设min-height: 100dvh或显式高度 → 子元素100dvh实际计算为 0 - 对
position: absolute元素,更稳妥的是用top: 0; bottom: 0;替代height: 100dvh,只要父容器是position: relative或fixed - 若父容器靠 JS 动态
--vh驱动,需确保变量已初始化完成,否则子元素读到的是初始1px
JS 动态设 --vh 是最稳兜底方案
当遇到 iOS 15 及以下、微信内置 WebView、或某些 dvh 行为不稳定环境时,JS 是唯一能精确响应每次视口变化的路径。
- 必须在
DOMContentLoaded后立即执行一次,否则首屏渲染用的是地址栏未收起时的错误初始值 - 后续监听
resize和scroll(加防抖),因为地址栏收放、键盘弹出、横竖屏切换都会改变window.innerHeight - 注意:
html和body上不能有transform、filter、opacity等创建新层叠上下文的属性,否则会干扰window.innerHeight取值和--vh生效
复杂点在于:所有修复都得从全局高度源头(html)开始逐层收敛,一个漏掉的 right: -5px、一张没设 max-width: 100% 的图、或 html 上残留的 width: 100vw,都可能叠加出溢出。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











