The Idea
Lenis smooth scroll library is INCOMPATIBLE with CSS scroll-snap. They fight for scroll control.
Context
Wedding invitation site had both Lenis (for smooth parallax scrolling) and CSS scroll-snap (for section-by-section navigation). Neither worked properly.
Raw Exchange
Librarian agent research: “CRITICAL: Lenis and CSS scroll-snap are INCOMPATIBLE - Lenis hijacks native scrolling” Solution: “Remove Lenis, use CSS scroll-snap + native smooth scroll for better mobile performance”
Investigation
Lenis works by:
- Intercepting wheel/touch events
- Applying its own scroll animation via
requestAnimationFrame - Updating scroll position programmatically
CSS scroll-snap expects:
- Native scroll behavior
- Browser to handle snap points
- No interference with scroll position
When combined:
- Lenis animates scroll → browser tries to snap → Lenis overrides → janky behavior
- Mobile especially broken (touch events fight)
Resolution
Removed Lenis entirely:
// Before (Layout.astro)
import Lenis from 'lenis';
const lenis = new Lenis({ ... });
lenis.on('scroll', ScrollTrigger.update);
// After
// Just GSAP ScrollTrigger, no Lenis
gsap.registerPlugin(ScrollTrigger);
Added native smooth scroll:
html {
scroll-behavior: smooth;
scroll-snap-type: y proximity;
}
section {
scroll-snap-align: start;
}
Lesson
Don’t mix scroll-hijacking libraries with CSS scroll-snap. Choose one:
- Lenis/Locomotive: Complex custom scroll experiences, no snap
- CSS scroll-snap: Section-based navigation, simpler, better mobile performance
Expansion Potential
Article: “Why Lenis Broke My Scroll-Snap (And How I Fixed It)”
- Common gotcha for developers combining smooth scroll libs with snap
- Debugging steps: check if library uses
scrollTo()or position manipulation - Alternative: GSAP ScrollTrigger
snapproperty (works with native scroll)