uni-app 中无法固定状态栏,需用 navigationstyle: "custom" 启用自定义导航栏;推荐用 position: sticky + 动态 --status-bar-height 实现吸顶,避免 scroll-view 包裹、overflow/transform 干扰,并注意横竖屏重置变量。

uni-app 里没有“固定状态栏”这个操作——状态栏是系统级 UI,无法由前端代码直接固定或控制其滚动行为。你真正想实现的,是让自定义导航栏(或顶部内容)在页面滚动时保持吸顶、不被滚走,同时避开状态栏区域,避免文字被遮挡。
为什么 navigationStyle: "custom" 是前提
默认导航栏由系统渲染,uni-app 无法干预其位置和滚动行为;启用自定义导航栏后,你才能完全掌控顶部区域的 DOM 和样式。必须在 pages.json 对应页面配置中明确设置:
"style": {
"navigationStyle": "custom"
}
否则所有吸顶逻辑都会失效——onPageScroll 在 custom 模式下才稳定触发,且 DOM 可自由定位。
用 position: sticky 实现真·轻量吸顶
比监听 onPageScroll 更简洁、性能更好,也无需手动计算偏移。前提是:父容器不能有 overflow: hidden 或 transform 等破坏粘性定位的属性。
-
sticky元素需设top值,推荐用top: calc(var(--status-bar-height) + 0px)动态适配 - 必须在
onMounted中通过uni.getSystemInfoSync().statusBarHeight注入 CSS 变量,例如:document.documentElement.style.setProperty('--status-bar-height', `${systemInfo.statusBarHeight}px`) - 不要把 sticky 元素包在
scroll-view内——它会创建新的层叠上下文,使sticky失效
滚动时导航栏变色/显隐的常见翻车点
很多人用 onPageScroll 判断 scrollTop 来切换类名,但容易出错:
- 未做节流,高频触发导致卡顿;建议用
setTimeout防抖,延迟 50ms 再更新isScrolled - 忽略 App 端原生渲染要求:App 平台必须开启
usingComponents: true(vue.config.js),否则onPageScroll在某些机型上不触发 - 误用
v-show控制显隐——它只是切display,没有过渡效果;要用transform: translateY()+transition才能平滑动画 - H5 端若用
scroll-view包裹全页,onPageScroll将完全不触发,因为滚动事件被截获了
最易被忽略的是:状态栏高度只在首次加载时获取一次,但横竖屏切换时 statusBarHeight 可能变化(尤其 iPad),需要监听 resize 事件重新读取并更新 CSS 变量。











