uni-app H5端页面高度塌陷源于iOS Safari对vh的动态重算,应禁用vh适配,改用rem+动态监听resize/orientationchange并延时更新根字体大小,避免依赖window.innerHeight即时值。
打开H5页面后,page 或 view 内容没撑开,底部留白、滚动条失效、vh 计算错乱——这不是 CSS 写错了,是移动端浏览器(尤其 iOS Safari)对 vh 的实现不一致导致的。iOS Safari 在地址栏收起/展开时会动态重算 vh,但 uni-app 默认用的是 vh 做视口基准,结果就是“高度突然缩水”。
vh 适配,改为使用 px + 动态计算uni-app 的 vue.config.js 或者 manifest.json 中默认启用 viewport 适配,它会将 750rpx 转换为 100vw,但 vw 又依赖 vh 行为,因此无法绕过塌陷。最可靠的办法是将其关闭,改由手动接管:
manifest.json 中配置 "display":"standalone"(并非必需,但可以降低 Safari 地址栏的干扰)main.js 或 App.vue 的 onLaunch 中执行:const doc = document.documentElement;doc.style.fontSize = window.innerHeight / 10 + 'px'; // 把 100vh 拆成 10 份,1rem ≈ 10vh
rem,例如 height: 10rem ≈ 满屏高度;不要直接使用 height: 100vh
window.innerHeight 不稳定时如何处理直接读取 window.innerHeight 时,iOS Safari 在页面初次载入或地址栏变化后经常更新滞后,例如横竖屏切换完成,数值仍是旧值。因此不能只在 onload 时赋值一次。
resize 与 orientationchange 事件,但需要注意 iOS Safari 的 resize 可能无法及时触发setTimeout 延迟重算,例如:function updateRootFontSize() { setTimeout(() => { const h = window.innerHeight || document.documentElement.clientHeight; document.documentElement.style.fontSize = h / 10 + 'px'; }, 100);}window.addEventListener('resize', updateRootFontSize);window.addEventListener('orientationchange', updateRootFontSize);
uni.navigateTo 切换页面,目标页面也要再次调用,因为有些机型切页之后 innerHeight 仍未更新env(safe-area-inset-bottom) 处理塌陷env(safe-area-inset-bottom) 的用途是为刘海屏/Home Indicator 预留空间,与高度塌陷并无关系。它不能修复 vh 动态变化,反而可能把底部区域错误识别为“不可用”,使可用高度被进一步压缩。
真正需要防范的并非安全区,而是 Safari 对 vh 的“延迟更新”。因此不能依赖 CSS 环境变量兜底,必须通过 JS 主动同步视口的真实高度。
复杂之处在于,不同 iOS 版本触发 resize 的时机差别很大,某些版本甚至必须监听 scroll 才能捕捉地址栏变化。正式上线前,应使用 Safari 远程调试在真机上反复验证横竖屏切换、调出键盘、进入后台后返回等场景。