iOS Safari中100vh“缩水”是因地址栏动态变化导致视口高度重算而uni-app未实时感知,应使用uni.getSystemInfoSync()动态获取windowHeight并减去导航栏高度来适配。
不是你CSS写错了,是iOS Safari对vh的实现本身就有缺陷:地址栏收起/展开时会动态重算100vh,但uni-app加载时只读了一次window.innerHeight,后续变化它不感知。结果就是页面刚打开时正常,一滚动或切横屏,高度突然塌陷、底部留白、scroll-view撑不满。
uni.getSystemInfoSync()动态设高度最稳别依赖CSS里的100vh,直接用JS获取真实可用视口高度,再绑定到元素上。这是目前H5端兼容性最好的方案。
uni.getSystemInfoSync()返回的windowHeight是纯内容区高度,不含地址栏、状态栏等干扰onLoad和onShow里都调一次,因为部分安卓机型切页后windowHeight不刷新88rpx或100rpx),不能只靠100vh硬减示例:
export default { data() { return { windowHeight: 0 } }, onLoad() { this.setPageHeight() }, onShow() { // 防止切页后高度失效 setTimeout(() => this.setPageHeight(), 100) }, methods: { setPageHeight() { const info = uni.getSystemInfoSync() this.windowHeight = info.windowHeight - 88 // 减去自定义顶部tab高度 } }}
...
vh适配,改用rem + 动态根字号如果你的项目大量用了rpx或rem,且需要横竖屏平滑切换,直接关掉uni-app默认的vh基准更彻底。
manifest.json里确认没开viewport相关自动适配(尤其避免"scale": true)App.vue中手动设置document.documentElement.style.fontSize,用window.innerHeight / 10 + 'px'作为1rem基准resize和orientationchange,但iOS Safari触发滞后,得套一层setTimeout延时更新scroll-view内部若用vh单位,依然会塌,得统一改成rem或px
calc(100vh - Xpx)
很多人想用CSS减法“修”高度,比如height: calc(100vh - 44px),但在H5端这招容易翻车。
100vh本身就不稳定,再减固定像素,误差会放大44px或50px不可靠#ifdef H5能隔离平台,但不能解决vh本身的计算缺陷calc,至少配合env(safe-area-inset-bottom)和--status-bar-height变量,但这些仅对安全区有效,不解决主视口塌陷真正容易被忽略的点:H5端page组件不是滚动容器,body才是。所以overflow: hidden加在.page上没用,得作用于html或body才生效——这点和小程序、APP端逻辑完全不同。