移动端H5中100vh不等于真实可视高度,因浏览器地址栏动态显隐而CSS的100vh在加载时固化;应优先用100dvh,不支持时用window.innerHeight动态设置--vh变量并配合calc()降级,uni-app中推荐uni.getSystemInfoSync()获取windowHeight。

移动端 H5 中 100vh 不等于真实可视高度,根本原因是浏览器地址栏、工具栏会动态显隐,而 CSS 的 100vh 在页面加载时就固化为初始视口高度,后续滚动或 UI 变化它不响应。iOS Safari 尤其明显:刚打开时地址栏可见,100vh 偏小;一滚动地址栏收起,100vh 却不变,导致底部留白或内容被裁。安卓部分机型也有类似问题。
用 window.innerHeight 动态获取真实高度
这是最通用、兼容性最好的方案。浏览器每次地址栏变化或屏幕旋转,window.innerHeight 都会返回当前「眼睛真正能看到的区域」高度(不含状态栏、地址栏等不可见 UI)。
- 在页面初始化时调用一次,确保首次渲染正确
- 监听
resize和orientationchange事件,地址栏收起/展开、横竖屏切换都会触发 - 将结果转为 CSS 自定义变量,供全局使用:
document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`) - CSS 中写成
height: calc(var(--vh, 1vh) * 100),回退值保证降级可用
优先尝试 100dvh(现代浏览器首选)
dvh(dynamic viewport height)是专为解决这个问题设计的标准单位,能随地址栏、键盘弹起等实时变化,比 100vh 更贴近用户当前可见区域。
- 直接写
height: 100dvh即可,无需 JS 干预 - 适用于 Chrome 105+、Safari 16.4+、Edge 105+ 等较新版本
- 不支持时需降级:用
@supports not (height: 100dvh)包裹 fallback 样式,内部走 JS 方案 - 注意:微信内置浏览器、部分安卓 WebView 仍不支持,不能单独依赖
uni-app 项目中推荐用 uni.getSystemInfoSync()
uni-app 的 uni.getSystemInfoSync() 返回的 windowHeight 是纯内容区高度,已排除状态栏、导航栏干扰,比 window.innerHeight 更稳定可靠。
- 必须在
onLoad和onShow都调用一次,避免安卓切页后高度未更新 - 若页面含自定义导航栏(如 uni-app 的
navigationStyle: custom),需额外减去对应高度(常见为 88rpx 或 100rpx) - 绑定到 data 或 computed 中,再通过 :style 绑定到容器上,例如:
:style="{ height: windowHeight + 'px' }" - 避免直接写
100vh,尤其不要在 scroll-view、page 容器上硬设
避开常见陷阱
很多“看似正常”的写法在真机上会翻车:
-
height: 100%不可靠——它依赖父级高度链,一旦 html/body 没设满,整个链就断了 -
100lvh(large viewport height)适合全屏沉浸场景,但地址栏显示时会撑高内容,导致底部被遮 -
100svh(small viewport height)偏保守,地址栏收起后顶部留白明显 - 只监听
resize不够——iOS Safari 滚动时地址栏隐藏不触发 resize,必须加scroll节流判断或用visualViewportAPI 补充


















