需手动获取statusBarHeight并动态设置自定义导航栏的padding-top或top值,不可依赖CSS变量env(safe-area-inset-top),因小程序真机不支持;同时须用uni.getMenuButtonBoundingClientRect()适配胶囊按钮位置。

小程序端 navigationStyle: "custom" 后内容被状态栏遮挡
这是最常见也最容易误判的问题:配置了 navigationStyle: "custom",页面内容直接顶到屏幕最顶部,第一行文字被时间、信号图标盖住。这不是样式没生效,而是微信小程序移除了原生导航栏后,**完全不预留状态栏空间**,<view> 默认从 y=0 开始渲染。
必须手动读取并应用状态栏高度,且不能只靠 CSS 变量——部分低端安卓机或旧版微信不支持 env(safe-area-inset-top)。
- 在页面
onLoad或onShow中调用uni.getSystemInfoSync()获取statusBarHeight - 把该值存为 data 或 ref,在 template 中绑定到自定义 header 的
style上,例如::style="{ 'padding-top': statusBarHeight + 'px' }" - 若使用
position: fixed自定义导航栏,需同时设置top: statusBarHeight + 'px',否则会压在状态栏下方 - 别只写
margin-top: var(--status-bar-height)—— H5 支持,但小程序真机上这个 CSS 变量不一定被注入,不可靠
APP 端自定义 header 与安全区域对齐
APP 端(iOS/Android)的“状态栏”是系统级 UI,不是网页概念。即使隐藏了原生导航栏,状态栏仍存在;iPhone X 及以上机型还有刘海区,顶部有非矩形安全区域。
env(safe-area-inset-top) 是唯一跨平台可用的安全区域方案,但它只在 navigationStyle: "custom" + titleNView: false 组合下才真正生效。单独设 navigationBarHidden: true 在 APP 端完全无效。
- 自定义 header 的容器必须声明
padding-top: env(safe-area-inset-top),不能只用固定像素值 - 若同时需要兼容 iOS 和 Android,建议 fallback:
padding-top: max(var(--status-bar-height, 20px), env(safe-area-inset-top)) - 注意:某些 Android 厂商(如华为 EMUI、小米 HyperOS)对
env()支持不稳定,实测发现部分机型返回0px,此时仍需兜底读取uni.getSystemInfoSync().statusBarHeight - 不要给整个
<page>加padding-top—— 这会导致滚动时 header 与内容错位,应只作用于 header 自身或其父容器
胶囊按钮(微信右上角「…」)怎么不遮挡自定义 header
微信小程序强制显示胶囊按钮,且无法通过 CSS 隐藏(display: none、opacity: 0、z-index 全部无效),这是平台限制,不是 bug。
你只能适配它,而不是对抗它。关键点是:胶囊按钮的位置和尺寸是动态的,不同机型差异大(尤其全面屏 vs 非全面屏),必须实时测量。
- 用
uni.getMenuButtonBoundingClientRect()获取胶囊按钮的top、bottom、height,而非硬编码 44px 或 64px - 导航栏总高度 =
(menuButton.bottom - statusBarHeight) + (menuButton.top - statusBarHeight),这就是你自定义 header 应该设的高度 - 右侧留空区域宽度 =
menuButton.right - menuButton.left,把你的搜索框、图标等元素避开这个范围 - 如果只是想视觉上“融合”,可将自定义 header 背景设为透明或渐变,并让文字颜色与胶囊按钮一致(如深灰 #333),降低割裂感
为什么 H5 看着正常,一真机就错位
H5 端没有状态栏概念,navigationBarHidden: true 只是隐藏 uni-app 渲染的 title 区域,不影响浏览器地址栏;而小程序和 APP 端的状态栏是真实物理区域,必须参与布局计算。
最典型的错误是:在 pages.json 里写了 "navigationBarHidden": true,以为全平台生效,结果小程序和 APP 端导航栏还在,或者内容被遮挡。
- 跨端项目务必分平台写配置,不要共用同一套 style
- H5 可用
titleNView: false快速去标题,副作用小;小程序必须用navigationStyle: "custom";APP 必须二者都写:"navigationStyle": "custom"+"titleNView": false - 所有涉及状态栏的逻辑(读 height、设 padding、算胶囊位置)必须加条件编译:
#ifdef MP-WEIXIN/#ifdef APP-PLUS,否则 H5 会报错或行为异常 - 别在
mounted里读statusBarHeight—— 小程序环境可能未就绪,onLoad或onShow更稳妥
实际最难的不是写代码,是记住:状态栏不是“样式问题”,而是“布局坐标系起点”的偏移。每次你漏掉一次 statusBarHeight 补偿,页面就有一截内容永远看不见。


















