无限视差滚动别再只会做一次了,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,看看能不能做出更有层次感的“无限隧道”效果。

评论区

0 条评论

登录后可评论。

查看完整榜单
查看完整榜单
查看完整榜单