Lenis 平滑滚动完整指南:从 3 行代码到调优实战
2026/9/19 13:18:04 网站建设 项目流程

Lenis 平滑滚动完整指南:从 3 行代码到调优实战

【免费下载链接】lenisSmooth scroll as it should be项目地址: https://gitcode.com/GitHub_Trending/le/lenis

做 WebGL 交互或者 GSAP 视差动画的朋友,大概率遇到过这个场景:原生滚动是浏览器"抢着"管理的,你的动画脚本想读取一个连续的、可控的滚动值,却发现它和页面真实位置不同步,视差效果一快就穿帮。Lenis 就是为这类问题而生的轻量级平滑滚动库——它接管滚动手感,把滚动变成一个可预测、可驱动的数值流。库名 Lenis 在拉丁语里就是"平滑"的意思。

先认识一下 Lenis

Lenis 由 darkroom.engineering 开发,定位是"小而全"的滚动内核:

  • 体积很小、零运行时依赖:整个库只有几 KB(官方 README 表述为 a few KB)
  • 基于原生滚动:它包裹浏览器的真实滚动而不是伪造一个,所以position: sticky、锚点链接、无障碍能力照常工作
  • 任意方向:垂直、水平、嵌套容器,同一个 API
  • 为同步而生:一个 rAF 循环同时驱动 WebGL 场景、GSAP ScrollTrigger 和视差效果
  • 官方适配器:React、Vue、Framer 各有一等公民包
  • 配套插件lenis/snap补上 CSS scroll-snap 的能力

适合:落地页、作品集、3D 滚动叙事、需要滚动与动画精确联动的页面。 不适合:对"像素级还原原生滚动行为"有洁癖的场景——平滑滚动本质上是"浏览器先到、你的动画跟拍",理解了这个前提就不会失望。

三步跑通:安装到看到丝滑效果

先安装(包名是lenis,不是旧文章里常见的@studio-freight/lenis):

npm i lenis

然后是官方推荐的最短启动方式,开了autoRaf就不用自己写动画循环:

import Lenis from 'lenis' import 'lenis/dist/lenis.css' // 官方推荐样式,务必引入 const lenis = new Lenis({ autoRaf: true }) // 每个滚动帧都会触发,回调参数就是 Lenis 实例本身 lenis.on('scroll', (lenis) => { console.log(lenis.scroll, lenis.velocity, lenis.progress) })

如果你要把 Lenis 挂到别的时间轴上(GSAP、Framer Motion 都是这么干的),就关掉autoRaf,自己每帧调用raf(time),时间单位是毫秒:

const lenis = new Lenis() function raf(time) { lenis.raf(time) // 每帧推进一次内部动画 requestAnimationFrame(raf) } requestAnimationFrame(raf)

推荐样式文件里做了几件关键事:恢复html高度、平滑滚动时对 iframe 关闭pointer-events、给data-lenis-prevent元素加overscroll-behavior: contain。跳过这一步是很多"不生效"问题的根源。

不想写代码也能用:HTML 里直接挂脚本标签并传{ autoRaf: true, autoToggle: true, anchors: true, allowNestedScroll: true, stopInertiaOnNavigate: true },官方称之为 no-code 用法,能顺带处理好锚点、嵌套滚动和页面切换时的惯性重置。

原理拆解:一个目标值、一条追赶曲线

Lenis 的核心不复杂,源码里有一句话式的注释,值得先读(packages/core/src/lenis.ts):

监听 wheel → 阻止默认滚动 → 归一化 delta → 累加到 targetScroll → 把真实滚动动画地推向 targetScroll

它维护着两个关键数值:

  • targetScroll:用户"想要"的位置(滚轮、触摸累加出来的目标)
  • animatedScroll:当前"正在呈现"的位置,最终通过wrapper.scrollTo(..., { behavior: 'instant' })写回浏览器

两者之间的追赶由 Animate 类 完成,支持两种模式:

// animate.ts 的核心分支 if (this.duration && this.easing) { // 时间驱动:按 easing 曲线在固定时长内走完 this.value = this.from + (this.to - this.from) * easedProgress } else if (this.lerp) { // 插值驱动:指数阻尼,帧率无关 this.value = damp(this.value, this.to, this.lerp * 60, deltaTime) // damp = lerp(x, y, 1 - Math.exp(-lambda * dt)) }

默认走 lerp 模式(lerp: 0.1),用1 - e^(-λ·dt)做阻尼——这意味着 60Hz 和 144Hz 的屏幕上手感一致,不会因为帧率高就追得更快。而 wheel/touch 事件先经过 VirtualScroll 归一化:不同设备的deltaMode(像素/行/页面)被统一换算,再乘以wheelMultiplier/touchMultiplier,这就是"手感可调"的入口。

滚动状态也会以类名的形式暴露给 CSS:lenis-scrollinglenis-smoothlenis-stopped,方便你在样式层做联动。

配置项全表:哪些参数决定"手感"

以下默认值均来自 官方 README 的 Settings 一节:

参数类型 / 默认值对手感/行为的影响
lerpnumber /0.1默认模式。越大追赶越快,手感越"贴手",越小越拖尾
durationnumber /1.2时间驱动模式的总时长(秒),需与easing搭配
easingfunction / 内置指数衰减决定收尾曲线;只给 easing 不给 duration 时时长按 1s 处理
smoothWheelboolean /true滚轮是否走平滑,关掉则滚轮为原生滚动
syncTouchboolean /false让触摸也模拟轮式平滑(惯性),iOS 16 以下可能不稳定
syncTouchLerpnumber /0.075触摸惯性阶段的插值强度
touchInertiaExponentnumber /1.7抬手后惯性甩动的衰减强度
wheelMultipliernumber /1滚轮灵敏度,整体放大/缩小输入
touchMultipliernumber /1触摸灵敏度,同上
overscrollboolean /true类似 CSSoverscroll-behavior,控制到顶/底后是否再触发浏览器回弹
anchorsboolean /false默认平滑滚动会拦截锚点;开启后点锚点走scrollTo
infiniteboolean /false无限滚动,scroll属性在 limit 内取模循环
orientationstring /verticalverticalhorizontal
allowNestedScrollboolean /false自动放行嵌套滚动容器,但每帧查 DOM 有性能开销
autoRafboolean /false是否内置 rAF 循环
autoToggleboolean /false根据容器 overflow 自动启停,需配合推荐 CSS
stopInertiaOnNavigateboolean /false点击站内链接时立即停止惯性,避免翻页后还在滑

常用方法与属性也值得记住:

  • scrollTo(target, options):目标可以是数字(px)、CSS 选择器、关键词(top/bottom/start/end)或 DOM 元素;options支持offsetimmediate(瞬移)、lock(到达前禁止用户滚动)、onCompleteuserData
  • stop()/start()/destroy():暂停(常见于打开弹窗时)、恢复、销毁
  • 事件scroll(参数是 Lenis 实例,可顺手读progressvelocitydirection)和virtual-scroll(参数{deltaX, deltaY, event},可在此拦截输入)

实战组合:动画库与框架

GSAP ScrollTrigger:官方给定的四行配方

const lenis = new Lenis() lenis.on('scroll', ScrollTrigger.update) // 滚动变化时通知 ScrollTrigger gsap.ticker.add((time) => { lenis.raf(time * 1000) // GSAP 时间轴是秒,换算成毫秒 }) gsap.ticker.lagSmoothing(0) // 关闭 GSAP 滞后补偿,避免双重平滑

让 GSAP 的 ticker 当唯一时钟,Lenis 的插值和 ScrollTrigger 的 scrub 就共享同一帧,快速滚动时也不会掉帧错位。

React / Vue:官方适配器

React 侧用<ReactLenis root />创建全局实例,任意组件通过useLenis拿到它并注册每帧回调(packages/react/):

import { ReactLenis, useLenis } from 'lenis/react' function App() { useLenis((lenis) => { // 每个滚动帧执行,可做视差、进度条等 document.querySelector('.hero').style.transform = `translateY(${lenis.scroll * 0.2}px)` }) return <ReactLenis root>{/* 页面内容 */}</ReactLenis> }

Vue 侧对应<VueLenis root>vueLenisPlugin,用法同构,同样只在客户端环境初始化实例,天然规避 SSR 时触碰window的问题。Framer Motion 的接法是frame.update((data) => lenis.raf(data.timestamp), true)

lenis/snap:平滑滚动 + 分节吸附

原生 scroll-snap 在平滑滚动下会打架,官方给了 snap 插件 作为替代:

import Lenis from 'lenis' import Snap from 'lenis/snap' const lenis = new Lenis({ autoRaf: true }) const snap = new Snap(lenis) snap.addElement(document.querySelector('.intro'), { align: 'start', // 对齐方式:start / center / end }) snap.add(1200) // 也可以直接吸附到某个 px 值 // 翻页式交互:type 传 'lock' 时更像幻灯片

支持proximity/mandatory/lock三种模式,还有next()previous()goTo(index)供按钮调用。

踩坑与排障:官方列过的边界

这些限制官方在 Limitations 一节里写得明明白白,动手前先看:

  • Safari 上限 60fps,低电量模式只有 30fps——高刷屏上别指望 120fps 的滚动
  • iframe 内不生效:iframe 不转发 wheel 事件;推荐 CSS 会对.lenis-smooth iframepointer-events: none
  • macOS Safari(M1 之前)position: fixed有滞后的已知问题
  • syncTouch在 iOS 16 以下可能异常

开发中高频的四个坑及解法:

  1. 完全不滚:十有八九是漏了推荐 CSS,或既没开autoRaf也没手动调lenis.raf(time);先摘掉 Lenis 确认页面本身可滚
  2. 嵌套滚动容器(弹窗、侧栏)抢滚动:轻量的做法是给容器加data-lenis-prevent属性(还有-wheel-touch-vertical-horizontal细分变体);allowNestedScroll: true是自动方案但每次滚动都查 DOM,性能敏感页面优先用属性
  3. 锚点失效:平滑滚动默认拦截锚点,传anchors: true即可,还能给offsetonComplete
  4. 翻页后还在滑:单页应用路由切换时加stopInertiaOnNavigate: true,或自己lenis.reset()/destroy()清理

入口与延伸

一句话总结:Lenis 用几 KB 的代码把"滚动"从一个不可控的浏览器行为,变成了一个每帧可读、可驱动、可调手的数值流——这是它能同时服务普通官网和 3D 叙事页面的原因。

  • 完整 API 与选项说明:README.md
  • 核心实现(Lenis 主类、Animate、VirtualScroll):packages/core/src/
  • 各框架适配器:packages/react/、packages/vue/
  • 分节吸附插件:packages/snap/
  • 设计动机(为什么它最初是为 WebGL 同步而生的):MANIFESTO.md

项目为 MIT 协议,社区里还有 r3f-scroll-rig、locomotive-scroll 等基于 Lenis 的第三方插件可以直接选用。🚀

【免费下载链接】lenisSmooth scroll as it should be项目地址: https://gitcode.com/GitHub_Trending/le/lenis

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询