尧图精选

Lenis:轻量级平滑滚动库手册——3 个核心机制 + 4 个实战场景 + 配置速查

🕒 发布时间:2026/9/19 16:17:20 📁 来源:尧图网络
Lenis轻量级平滑滚动库手册——3 个核心机制 4 个实战场景 配置速查【免费下载链接】lenisSmooth scroll as it should be项目地址: https://gitcode.com/GitHub_Trending/le/lenisLenis 是一款轻量级、零依赖的平滑滚动库仅数 KB 体积它包裹浏览器原生滚动而非用 transform 伪造位移因此 sticky 与锚点链接原样保留。适合需要做视差、WebGL 滚动同步、滚动驱动动画的前端开发者。读完你能完成初始化、调参并接入 GSAP 与 React/Vue 生态。快速上手三步开启平滑滚动安装npm i lenis然后在入口文件里引入、初始化、加上推荐 CSS共三步。import Lenis from lenis import lenis/dist/lenis.css // 推荐 CSS负责 stopped 态与嵌套容器的 overscroll 行为 // autoRaf: true 让实例内部自动跑 requestAnimationFrame 循环 // 不开启的话必须每帧手动调 lenis.raf(time) const lenis new Lenis({ autoRaf: true }) // 位置变化的每一帧都会触发progress / velocity 等属性直接读实例即可 lenis.on(scroll, (e) { console.log(e.animatedScroll, e.progress) }) // 参考 README Setup 一节实例定义见 packages/core/src/lenis.ts不想搭构建环境也有一行版HTML 里引lenis.css和lenis.min.js然后执行new Lenis({ autoRaf: true, autoToggle: true, anchors: true, allowNestedScroll: true, naiveDimensions: true, stopInertiaOnNavigate: true })README 的 No-code usage 一节列出了这组全功能参数组合能顺带处理模态框、锚点、页面切换时的滚动复位。想看源码可以直接 clonegit clone https://gitcode.com/GitHub_Trending/le/lenis。核心机制拆解轻量与顺滑背后的 3 个设计决策包裹原生滚动而不是用 transform 伪造设计意图多数平滑滚动库用虚拟画布方案——把页面塞进容器、用 transform 位移来模拟滚动。Lenis 反其道而行真正调用浏览器滚动。packages/core/src/lenis.ts文件头的注释把链路写得明明白白监听wheel事件并preventDefault阻止原生跳动 → 归一化 delta → 累加进targetScroll→ 平滑地把scrollTo动画到目标值没有动画在跑时则退化为监听原生scroll事件。与传统做法的差异一目了然对比项Lenis原生滚动方案传统 transform 虚拟滚动实现方式真实scrollTo({ behavior: instant })驱动 window对容器做 translate 位移position: sticky/ fixed原样生效会失效需额外补偿锚点链接、键盘可达性原样保留需手工重建收益是 README 里 Runs on native scroll 那条特性position: sticky、锚点链接和无障碍交互全部不牺牲。注意setScroll里特意用behavior: instant就是为了绕过页面自己声明的scroll-behaviorCSS避免双重平滑。两种手感二选一damp 插值与固定时长缓动 Lenis 的手感由Animate类packages/core/src/animate.ts提供它不是一种算法而是两种// 参考 packages/core/src/animate.tsadvance 方法摘录 advance(deltaTime: number) { if (this.duration this.easing) { // 模式一时间驱动。按 duration 走完整条 easing 曲线 this.currentTime deltaTime const linearProgress clamp(0, this.currentTime / this.duration, 1) const easedProgress linearProgress 1 ? 1 : this.easing(linearProgress) this.value this.from (this.to - this.from) * easedProgress } else if (this.lerp) { // 模式二指数阻尼。damp 公式 1 - e^(-lambda·dt)帧率无关 this.value damp(this.value, this.to, this.lerp * 60, deltaTime) } else { // 两者都没给直接跳到终点 this.value this.to } }差异点传统库通常只给一组固定缓动曲线帧率一波动手感就漂移。damp用1 - Math.exp(-lambda * dt)packages/core/src/maths.ts做到帧率无关60Hz 和 120Hz 屏幕上衰减曲线一致默认lerp: 0.1一个数就能调滑多远给duration easing则走标准时间轴默认缓动是Math.min(1, 1.001 - 2 ** (-10 * t))。收益滚轮的滑行感更接近真实惯性而不是匀速补间。先归一化输入再统一状态输出不同硬件的滚轮 delta 量纲完全不同像素、行、页面。packages/core/src/virtual-scroll.ts把deltaMode统一换算按行滚动的设备乘以LINE_HEIGHT 100 / 6按页滚动的乘以视口尺寸再乘wheelMultiplier/touchMultiplier。触摸端还补了两处细节touchend时按sign(delta) × |velocity|^1.7touchInertiaExponent默认 1.7模拟抬手后的惯性滑行iOS 上如果手指落在文本选区手柄 40px 半径内lenis.ts的isTouchOnSelectionHandle会把事件让给系统去调整选区而不是滚动。输出侧则把状态写成 CSS 类lenis、lenis-smooth、lenis-stopped、lenis-locked随状态自动增删。配套packages/core/lenis.css做了三件小事——html.lenis { height: auto }修正页面高度给data-lenis-prevent元素加overscroll-behavior: contain防链式回弹lenis-smooth期间给 iframe 加pointer-events: none防止 iframe 吞掉 wheel 事件。另外原生滚动停下 400ms 后velocity归零、isScrolling复位动画结束后还会派发自定义scrollend事件方便下游做滚动停止逻辑。实战场景几乎一定会遇到的 4 个需求让嵌套容器保持原生滚动场景页面里有抽屉、模态框或横向卡片列表落在它们上面滚动时不希望外层页面跟着滚。思路两档粒度。粗粒度开allowNestedScroll实例会自动检测可滚动子元素并放行原生滚动细粒度用data-lenis-prevent属性另有-wheel、-touch、-vertical、-horizontal变体或prevent回调在事件冒泡路径上精确豁免。// 参考 README Nested scroll 一节 const lenis new Lenis({ allowNestedScroll: true, // 粗粒度自动识别嵌套可滚动元素 // 细粒度二选一给元素加>// 参考 README GSAP ScrollTrigger 一节 const lenis new Lenis() // 每帧把 Lenis 的滚动状态喂给 ScrollTrigger lenis.on(scroll, ScrollTrigger.update) // 用 GSAP 的 ticker 驱动 Lenis gsap.ticker.add((time) { lenis.raf(time * 1000) // ticker 的时间单位是秒转成毫秒 }) // 关闭 GSAP 的滞后平滑否则快速滚动会累积延迟 gsap.ticker.lagSmoothing(0)坑gsap.ticker回调的时间单位是秒漏乘 1000 会让动画慢十倍lagSmoothing(0)忘了关快速滚动时动画与位置脱节这是 README Troubleshooting 里专门点名的一条。开启无限滚动模式场景品牌页、作品集的网格希望滚到尽头回到开头。思路一个开关infinite: true。开启后scroll取值器会用modulo(animatedScroll, limit)按回卷值输出scrollTo的目标也会自动选距离最近的方向超过limit / 2就往回绕。// 参考 playground/infinite/test.ts new Lenis({ infinite: true, // 循环滚动scroll 取值器按 limit 自动取模 autoRaf: true, syncTouch: true, // README 注明触摸设备开启 infinite 需要它 })坑触摸设备上必须同时开syncTouch: true否则惯性触摸会直接打断回卷逻辑。搭建横向滚动区段场景产品画廊、步骤展示需要一段横向滚动的区域。思路不用全局实例单独new Lenis({ wrapper: 容器, orientation: horizontal })挂在具体容器上scrollTo支持right、end等关键字。坑orientation设为horizontal时gestureOrientation默认自动变both见lenis.ts构造参数默认值横向纵向的 delta 都会进来如果你的横向区段嵌在纵向页面里注意用eventsTarget收窄监听范围并配合overscroll控制边界处的行为。配置速查常用参数与调优点核心参数默认值均可在packages/core/src/types.ts的 JSDoc 中核对参数默认值作用autoRaffalse实例内部自跑requestAnimationFrame循环不开则需手动lenis.raf(time)lerp0.1滚轮平滑的线性插值强度0~1定义滑行距离duration未设置回落 lerp 模式动画时长秒与easing配套一旦提供lerp即被忽略easing(t) Math.min(1, 1.001 - 2 ** (-10 * t))时间模式下的缓动曲线smoothWheeltrue滚轮输入是否走平滑syncTouchfalse模拟原生触摸滚动并同步位置iOS16 可能不稳syncTouchLerp0.075触摸惯性阶段的插值系数touchInertiaExponent1.7触摸抬手后的惯性强度指数wheelMultiplier/touchMultiplier1滚轮 / 触摸输入灵敏度orientationvertical滚动轴向horizontal需配合具体wrapperinfinitefalse无限循环滚动overscrolltrue类 CSSoverscroll-behavior的边界回弹anchorsfalse接管锚点链接点击并平滑滚动allowNestedScrollfalse自动放行嵌套可滚动元素的滚动naiveDimensionsfalse用简化的尺寸计算有性能代价autoTogglefalse按 wrapper 的 overflow 自动 start/stopstopInertiaOnNavigatefalse点击站内链接时清除滚动惯性进阶参数3 条以内各附原因prevent: (node) boolean——按节点豁免平滑。比allowNestedScroll省因为不需要每次事件遍历 DOM。virtualScroll: (data) boolean——在输入被消费前改写或否决它返回false即放弃本次输入适合按住某个键时不平滑这类条件交互。naiveDimensions——改用scrollHeight - clientHeight直接算limit逻辑更简单README 标注有性能影响谨慎开启。性能调优3 条以内各附原因一定引入lenis.cssdata-lenis-prevent元素的overscroll-behavior: contain靠它生效少了会看到弹性回弹把外层页面带滚。scroll事件每帧触发回调里只读随实例带来的scroll/progress/velocity都是现成属性零布局读取确需读布局就自行节流。页面尺寸完全固定时可设autoResize: false并手动调resize()内部ResizeObserver的重算本身带 250ms 防抖packages/core/src/dimensions.ts对静态页面是一次可省的开销。生态集成与常见问题接入 React 与 Vue 官方适配层Reactpackages/react/LenisProvider包裹应用后创建实例组件内用useLenis(callback, deps, priority)注册滚动回调回调按 priority 排序执行、卸载时自动移除packages/react/src/use-lenis.ts。Vue / Nuxtpackages/vue/同构的 provider useLenisNuxt 模块在packages/vue/nuxt/module.ts集成示例见playground/nuxt/plugins/lenis.ts。吸附插件packages/snap/new Snap(lenis, { type })snap.add(500 或元素)。type支持proximity默认、mandatory、lockdistanceThreshold默认50%、判定防抖 500mspackages/snap/src/snap.ts它监听的是 Lenis 的virtual-scroll事件不与主滚动逻辑打架。常见问题现象 → 原因 → 解决现象初始化后页面滚动毫无平滑感。原因autoRaf默认false内部动画没有每帧推进。解决开autoRaf: true或在自己的循环里每帧lenis.raf(time)README Troubleshooting 第一条。现象stop()之后仍能被滚。原因.lenis-stopped { overflow: clip }依赖推荐 CSS没引入lenis.css时类名没有实际效果。解决引入lenis/dist/lenis.css。现象锚点链接点了没反应。原因Lenis 默认在滚动期间拦截锚点行为。解决anchors: true或传ScrollToOptionshash 含特殊字符也能正常定位内部走decodeURIComponent解码lenis.ts的onClick。现象平滑滚动时 iframe 内容点不动。原因lenis.css在lenis-smooth期间故意给 iframe 加pointer-events: none防止它吞掉 wheel 事件导致滚动卡死。解决需要交互时给 iframe 外层加data-lenis-prevent。现象Safari 帧率卡在 60fps省电模式只剩 30fps。原因WebKit 对requestAnimationFrame的上限README Limitations 列出的已知 bug与系统省电策略。解决属环境限制而非参数问题不要为 Safari 单独加补帧逻辑。继续去哪儿核心源码packages/core/src/lenis.ts、选项类型与默认值packages/core/src/types.ts插件与适配层snap 吸附插件、React 适配层、Vue 与 Nuxt 模块可运行的演示playground 目录core / horizontal / infinite / snap / touch-debug 各有独立示例想深入原理先读 MANIFESTO.md参与开发看 CONTRIBUTING.mdlenis.ts文件头那六行注释加maths.ts里的damp就是这套滚动系统的全部骨架——改一个参数之前先看这两处比翻文档更快。【免费下载链接】lenisSmooth scroll as it should be项目地址: https://gitcode.com/GitHub_Trending/le/lenis创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →