← Zurück

Lenis Smooth Scroll

Warum fühlt sich native Scrolling "snappy" an — und wie Lenis das fixt.

❌ Das Problem mit Browser-Scroll

Native Browser-Scrolling springt direkt zur Zielposition.

Wheel Event → scrollTop = 500px // SOFORT

Das fühlt sich "snappy" an. Kein Gewicht, keine Trägheit, keine Physik.

✅ Die Lösung: Linear Interpolation (LERP)

Lenis interpoliert zwischen aktuellem und Ziel-Wert.

Frame 1: scroll = 0, target = 500 → scroll = 50

Frame 2: scroll = 50, target = 500 → scroll = 95

Frame 3: scroll = 95, target = 500 → scroll = 135

... smooth approach ...

lerp: 0.1 = 10% des Weges pro Frame → buttrig smooth

LERP — Das Herzstück

// Die Formel

newValue = currentValue + (targetValue - currentValue) * lerp

lerp: 0.1

Sehr smooth. Langsam. Premium-Feel.

lerp: 0.3

Balanced. Smooth aber responsive.

lerp: 1.0

Instant. Wie Browser-native.

Basic Setup

1. Installation:

npm install lenis

2. Minimal Setup (mit autoRaf):

import Lenis from 'lenis'
import 'lenis/dist/lenis.css'

const lenis = new Lenis({
  autoRaf: true,  // Automatischer RAF-Loop
  lerp: 0.1,      // Smooth-Faktor
})

// Optional: auf Scroll Events hören
lenis.on('scroll', (e) => {
  console.log(e.scroll, e.velocity)
})

GSAP ScrollTrigger Integration

import Lenis from 'lenis'
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'

gsap.registerPlugin(ScrollTrigger)

const lenis = new Lenis()

// 1. Lenis informiert ScrollTrigger über Scroll-Position
lenis.on('scroll', ScrollTrigger.update)

// 2. Lenis läuft im GSAP Ticker (perfekter Sync)
gsap.ticker.add((time) => {
  lenis.raf(time * 1000)
})

// 3. Kein Lag-Smoothing (würde Sync brechen)
gsap.ticker.lagSmoothing(0)

Warum funktioniert das? Lenis macht das Smooth-Scrolling, ScrollTrigger bekommt die interpolierten Werte und triggert Animationen basierend darauf.

Wichtige Properties

lenis.scroll

Aktueller (interpolierter) Scroll-Wert

lenis.targetScroll

Ziel-Wert (wo User hin will)

lenis.velocity

Scroll-Geschwindigkeit (für Effekte)

lenis.progress

0 bis 1 (für Progress-Bars)

lenis.direction

1 = down, -1 = up

lenis.isScrolling

"smooth" | "native" | false

Wichtige Methoden

lenis.scrollTo(target, options)

Programmatisch scrollen.

lenis.scrollTo('#section', { offset: -100, duration: 2 })
lenis.scrollTo(500, { immediate: true })  // Sofort, kein smooth
lenis.stop() / lenis.start()

Scrolling pausieren/fortsetzen. Für Modals!

lenis.destroy()

Cleanup. Wichtig bei React/Vue unmount!

Options verstehen

new Lenis({
  // Smooth-Verhalten
  lerp: 0.1,           // 0.05-0.2 ist sweet spot
  duration: 1.2,       // Ignoriert wenn lerp gesetzt!
  easing: (t) => ...,  // Ignoriert wenn lerp gesetzt!
  
  // Scroll-Richtung
  orientation: 'vertical',    // oder 'horizontal'
  gestureOrientation: 'both', // Touch-Gesten
  
  // Performance
  smoothWheel: true,   // Wheel Events smoothen
  syncTouch: false,    // Touch smoothen (instabil auf iOS!)
  
  // Nested Scrolling
  prevent: (node) => node.classList.contains('modal'),
  
  // Anchor Links
  anchors: true,  // Smooth scroll zu #anchors
})

Achtung: duration und easing werden von lerp überschrieben! Verwende entweder LERP oder Duration/Easing, nicht beides.

Nested Scrolling (Modals, etc.)

Mit HTML-Attribut:

<div data-lenis-prevent>
  <!-- Normales Scrolling hier -->
</div>

Mit JavaScript:

new Lenis({
  prevent: (node) => {
    return node.id === 'modal'
  }
})

React Integration

import { ReactLenis, useLenis } from 'lenis/react'

// Provider
function App() {
  return (
    <ReactLenis root options={{ lerp: 0.1 }}>
      <YourContent />
    </ReactLenis>
  )
}

// Hook
function Component() {
  const lenis = useLenis()
  
  const handleClick = () => {
    lenis?.scrollTo('#target', { duration: 1.5 })
  }
  
  return <button onClick={handleClick}>Scroll</button>
}

Performance-Tipps

autoRaf: true für einfache Setups
GSAP Ticker für komplexe Animationen (besserer Sync)
⚠️ syncTouch: false auf iOS (kann instabil sein)
⚠️ Safari ist auf 60fps gedeckelt (Hardware-Limit)
iframes brechen Smooth Scroll (forwarden keine Events)

✅ Was ich WIRKLICH verstanden habe