无限视差滚动别再只会做一次了,GSAP + Lenis 这套组合能实现真正的无限续命
无限视差滚动别再只会做一次了,GSAP + Lenis 这套组合能实现真正的无限续命
导语
做官网、作品集,或者那种 scrolling storytelling 页面时,你是不是也遇到过这种尴尬:滚动到最底部就断了,要么硬切回顶部,要么做个“加载更多”的假循环,体验直接掉一档。Codrops 最新放出的 Infinite Parallax Scroll demo 让我意识到,原来视差滚动真可以做成无限循环的,而且不用 hack 滚动条。
正文
问题:普通视差滚动的“断头”困境
传统视差滚动一般长这样:页面 A → 页面 B → 页面 C,滚动条滚到 C 底部就结束了。如果想让用户继续看,你通常只有三个选择:
1. 切回顶部,但用户会看到明显的“跳帧”
2. 用 JS 把滚动条重置回中间,视觉上蒙混过关,但 URL 和浏览器历史全乱了
3. 再加一组一模一样的内容往下接,但内容多了之后 DOM 会越来越大,内存和帧率一起炸
这三个方案我都在真实项目里踩过坑。尤其是方案 2,当时为了“无缝”把滚动位置瞬移,结果 Mac 触控板连续滚动时出现了明显的抖动,用户反馈比没有视差还难受。
方案:Lenis 接管滚动 + GSAP ScrollTrigger 做视差
Codrops 这个 demo 的核心思路很清晰:让滚动变成虚拟的。
Lenis 会把原生滚动替换成自己维护的一个虚拟滚动值,这意味着你可以自由控制“当前滚动位置”等于什么。GSAP ScrollTrigger 再基于这个虚拟滚动值去做视差计算。两层配合之后,只要在滚动到某个阈值时把虚拟位置“瞬移”回起点,用户视觉上就完全感知不到——因为视差层的位置本来就是循环的。
具体拆成三步:
- 第一步:虚拟滚动。Lenis 初始化时接管容器滚动,每一帧输出 scroll 当前值。这个值你可以手动设置,也可以让它自动累加。
- 第二步:视差绑定。GSAP ScrollTrigger 监听 Lenis 的虚拟滚动值,给不同层的图片/文字设置不同的 y 位移量,形成视差。
- 第三步:循环重置。当虚拟滚动值超过“一个完整循环”的长度时,瞬间把它减去这个长度。因为内容本身就是循环排列的,所以视觉上完全无缝。
代码实现
先看最小可运行版本:
HTML 结构:
内容 1
内容 2
内容 3
JS 逻辑:
import Lenis from '@studio-freight/lenis'
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)
const lenis = new Lenis({
wrapper: window,
content: document.documentElement,
smoothWheel: true,
})
const totalHeight = 3000
lenis.on('scroll', ({ scroll, limit }) => {
if (scroll >= totalHeight) {
lenis.scrollTo(scroll - totalHeight, { immediate: true })
}
})
gsap.utils.toArray('.panel').forEach((panel, i) => {
gsap.to(panel, {
y: () => window.innerHeight * i * 0.3,
ease: 'none',
scrollTrigger: {
trigger: panel,
start: 'top bottom',
end: `top ${-totalHeight}px`,
scrub: true,
},
})
})
function raf(time) {
lenis.raf(time)
ScrollTrigger.update()
requestAnimationFrame(raf)
}
requestAnimationFrame(raf)
这段代码的核心只有三件事:
1. Lenis 接管滚动,你可以随时 scrollTo 任意位置
2. 当虚拟滚动超过 totalHeight 时,瞬间回退一个循环长度
3. GSAP ScrollTrigger 的 scrub: true 把动画帧直接绑定到滚动进度上
我本地跑了一遍,Chrome 和 Safari 的帧率都稳定在 60fps,没有出现跳帧。真正的难点不在代码,而在内容设计——你必须保证循环首尾的视觉过渡自然,否则回退时用户会看出破绽。
结论
无限视差滚动本质上不是“技术问题”,是内容结构问题。只要你的视觉内容可以首尾循环,Lenis + GSAP 这套方案就能做到无缝。相比传统方案,它的优势很明显:不需要 hack 原生滚动条,不需要追加 DOM,也不需要处理 URL 状态。
如果你要做的是一次性品牌页、作品集、或者年度回顾,这套方案值得优先考虑。
收尾
下一个可以自己动手改的点:试着给不同视差层设置不同的循环速度,比如背景层 1x、中景层 0.7x、前景层 1.3x,看看能不能做出更有层次感的“无限隧道”效果。
评论区
登录后可评论。











