必须在index.html中添加viewport-fit=cover,并在app.vue中同时使用constant()和env()双写padding-bottom,且需js动态获取safearea.bottom值做fallback,否则ios h5底部按钮会被home indicator遮挡。

H5端在iOS Safari或微信WebView里底部按钮被Home Indicator遮住,不是CSS写错了,而是安全区没开启+fallback没兜底。
index.html 必须加 viewport-fit=cover
没这句,env(safe-area-inset-bottom) 在iOS H5里永远不生效,连 fallback 都救不了。很多开发者卡在这一步,改了一堆CSS却毫无反应。
-
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">要直接写进/src/index.html的里 - 不能只靠 manifest.json 或 App.vue 里的样式——那对 H5 无效
- HBuilderX 新建项目默认不带这行,必须手动补上
App.vue 全局 CSS 要双写 env + constant
仅写 env(safe-area-inset-bottom) 不够:iOS 11.2 以下用 constant(),iOS 11.2+ 才认 env(),且微信/抖音 WebView 完全不支持这两个,得靠 JS fallback 补位。
- 在
App.vue的<style></style>(非 scoped)里写:html, body, uni-app, uni-page-body { padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); } - 别漏掉
uni-page-body—— 否则 tabbar、scroll-view 等容器可能不生效 - 这个写法只对 Safari 和部分 Chrome 有效,微信 H5 仍需 JS fallback
JS fallback 必须动态取值,不能硬编码
有人写死 paddingBottom: "34px",结果在 iPhone 15 Pro Max 上按钮还是被遮半截——因为真机 safeArea.bottom 是动态的,从 34 到 48 px 都有。
- 在
App.vue的onLaunch或页面onShow里调用:const sys = uni.getSystemInfoSync() const bottom = sys.safeArea?.bottom || 0
- 把
bottom存到全局 data 或 vuex,再用::style="{ paddingBottom: bottom + 'px' }"绑定到关键容器 - 注意:H5 环境下
sys.safeArea可能为undefined,要加空值判断,否则报错
tabbar 页面要单独加 safe-area-bottom 类
内置 uni-tabbar 或 uView 自定义 tabbar 默认不响应安全区,光靠全局 padding 不够,容易出现“底部图标被切掉一半”。
- 给 tabbar 根元素加 class:
class="safe-area-bottom" - 对应 CSS 写:
.safe-area-bottom { padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); padding-bottom: var(--safe-bottom-fallback, 0px); } -
--safe-bottom-fallback是你 JS 设置的 CSS 变量,比如document.documentElement.style.setProperty('--safe-bottom-fallback', bottom + 'px')
真正麻烦的不是写几行代码,而是不同环境对安全区的支持断层太深:Safari 认 env,微信 WebView 什么都不认,Android H5 又完全不需要——所有 fallback 都得在运行时判端、取值、注入,漏掉任意一环,真机就出白条或遮挡。











