不能让导航栏真正“包含”状态栏,只能通过 fixed 定位+高度叠加(statusbarheight + titlebarheight)实现视觉融合;需关闭原生导航栏、js 动态获取双高度、css 配合占位防遮挡。

uni-app 自定义导航栏时,如何让导航栏高度「包含」状态栏
直接结论:不能让导航栏「包含」状态栏,但可以让导航栏「覆盖」状态栏实现视觉上的融合——这需要关闭原生导航栏 + 手动计算并设置总高度 = statusBarHeight + titleBarHeight,再用固定定位撑满顶部。
为什么不能真“包含”,而必须用 fixed + 高度叠加
uni-app 的 navigationStyle: "custom" 会隐藏系统原生导航栏(含状态栏区域),但不会自动把状态栏“塞进”你的自定义组件里。此时页面内容默认从屏幕顶部开始渲染,状态栏区域是透明的——你看到的「状态栏文字」其实是系统层叠在 webview 之上的,你的 view 默认不占那块空间。
所以所谓“包含”,本质是:用一个 position: fixed 的容器,高度设为 statusBarHeight + titleBarHeight,并确保它 top: 0;同时给页面主体加等高的 padding 或占位,避免被遮挡。
常见错误现象:
- 只设了
height: 44px,结果 iOS 上状态栏文字压在标题上 - 用了
var(--status-bar-height)但没配navigationStyle: "custom",变量始终为 0 - 在 H5 或 App 端直接套小程序逻辑,
uni.getMenuButtonBoundingClientRect()返回undefined
正确获取并组合两个高度的代码写法
关键点:必须区分平台、兜底、且在 DOM 渲染前就拿到值(推荐放在 onLoad 或 onMounted 中)。
示例(Vue 3 setup 语法):
const statusBarHeight = ref(20)
const titleBarHeight = ref(44)
<p>onLoad(() => {
const sys = uni.getSystemInfoSync()
statusBarHeight.value = sys.statusBarHeight || 20</p><p>// 小程序平台才存在胶囊按钮
if (uni.getMenuButtonBoundingClientRect) {
try {
const menu = uni.getMenuButtonBoundingClientRect()
titleBarHeight.value = menu.height + (menu.top - statusBarHeight.value) * 2
} catch (e) {
// 某些低端机或模拟器可能报错,降级为 44
titleBarHeight.value = 44
}
}
})
</p>
注意:
-
uni.getMenuButtonBoundingClientRect()在 H5 和 App 环境下不可用,需加判断 - 乘以 2 是因为:胶囊上下留白 =
top - statusBarHeight,所以总高 = 胶囊高 + 2 × 上边距 - 不要依赖
uni.getWindowInfo(),它在部分小程序平台返回不全(如抖音小程序)
样式层必须同步做的三件事
光有 JS 计算不够,CSS 必须配合,否则高度算对了也白搭。
- 自定义导航栏容器必须
position: fixed; top: 0; width: 100%; z-index: 999; - 容器内部用两个嵌套
view:一个设height: statusBarHeight(仅占位,常透明),一个设height: titleBarHeight(放标题/图标) - 页面主体最上方必须加一个等高占位
view,style 为height: statusBarHeight.value + titleBarHeight.value + 'px',否则内容会从屏幕顶上被遮住
容易被忽略的地方:iOS 刘海屏和安卓全面屏的 statusBarHeight 差异大(20px vs 30px),而胶囊按钮位置在不同机型也可能偏移,所以不要硬编码任何高度值——哪怕只是临时调试。











