滑动视差效果本质是监听页面滚动并动态修改导航栏样式:通过onpagescroll监听scrolltop,驱动背景位移(如translatey(-scrolltop*0.4))或透明度变化(如rgba(255,255,255,scrolltop/120)),需注意custom导航栏需自行实现、ios触发频率低、安卓渲染延迟及fixed元素抖动等问题。

滑动视差效果本质是监听页面滚动并动态修改导航栏样式
uni-app 里没有内置“导航栏视差”这个功能,所谓视差,就是用户往下滚动时,导航栏背景图移动速度比内容慢,产生层次感。关键不是改导航栏本身,而是监听 onPageScroll 事件,拿到 scrollTop,再用它驱动背景位移或透明度变化。
注意:这个事件只在非自定义导航栏(即 navigationStyle: "default")的页面生效;一旦设为 "custom",原生导航栏被隐藏,onPageScroll 仍可用,但你得自己控制一个固定定位的 DOM 元素来模拟导航栏,并手动绑定滚动逻辑。
- 真机调试时 iOS 上
onPageScroll触发频率偏低,别依赖它做高帧率动画,适合做渐变、位移等轻量过渡 - H5 端可配合
requestAnimationFrame平滑插值,小程序端建议用transform: translateY()而非top,避免重排 - 背景图视差慎用
background-attachment: fixed—— 小程序不支持,H5 在部分安卓机上会失真或卡顿
怎么让背景图“慢速移动”而不是直接消失
核心是把背景图的 transform: translateY() 值设为 -scrollTop * 0.3 这类缩放系数,实现“滚动 100px,背景只动 30px”的错觉。
示例中假设你有一个 <view class="nav-bar"></view>,里面包含 <image class="bg-parallax"></image>:
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 100rpx;
z-index: 999;
}
.bg-parallax {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-size: cover;
}
在 Vue 的 data 中存一个 parallaxOffset,并在 onPageScroll 里更新:
onPageScroll(e) {
const offset = e.scrollTop * 0.4;
this.parallaxOffset = Math.max(0, Math.min(offset, 60)); // 限制最大位移 60rpx
}
模板中绑定:
<image class="bg-parallax" :style="{ transform: 'translateY(' + parallaxOffset + 'rpx)' }"></image>
- 系数 0.4 是经验值,太大显得假,太小不明显;建议 0.2–0.5 区间内调试
- 务必加
Math.max(0, ...)防止负值导致背景上移出界 - 如果用了
custom导航栏,记得给容器加padding-top: status-bar-height + nav-height,否则内容会顶到状态栏下面
为什么透明度渐变比位移更稳妥
很多项目最终放弃位移,转而用背景色/文字透明度变化,因为兼容性更好、性能更高、逻辑更直白。
比如导航栏从透明到实色:
<view class="nav-bar" :style="{ backgroundColor: 'rgba(255, 255, 255, ' + navAlpha + ')' }"><text :style="{ color: navAlpha > 0.8 ? '#000' : '#fff' }">标题</text></view>
navAlpha 计算方式:
onPageScroll(e) {
// 滚动 0~120rpx 时,alpha 从 0 到 1
this.navAlpha = Math.min(1, e.scrollTop / 120);
}
- 120rpx 是触发完全不透明的距离,根据设计稿调整,常见 80–150rpx
- 颜色切换别用硬编码,建议用 CSS 变量或 computed 控制,避免重复计算
- 安卓低端机对
rgba()渲染有延迟,可加will-change: background-color提前提示渲染引擎
custom 导航栏下如何避免滚动抖动
自定义导航栏用 position: fixed 后,iOS 上容易出现“滚动一卡一卡”的现象,本质是 fixed 元素在某些机型上未启用硬件加速,或与页面滚动不同步。
必须做的三件事:
- 给导航栏容器加
transform: translateZ(0)或will-change: transform强制 GPU 加速 - 禁用页面默认滚动(
disableScroll: true),改用<scroll-view></scroll-view>包裹内容区,确保滚动源唯一 - 不要在
onPageScroll里直接修改大量样式,尤其避免操作width、height、left/top等触发布局的属性
最易忽略的一点:如果你在导航栏里嵌了 <input> 或 <textarea></textarea>,iOS 键盘弹起时 fixed 元素会错位——这时得监听 keyboardHeight 并动态调整 bottom 值,不能只靠 env(safe-area-inset-bottom)。











