Smooth Scroll Library Comparison
| Feature | Locomotive-scroll | GSAP ScrollSmoother | Lenis |
|---|---|---|---|
| Native scrollbar | ❌ | ✅ | ✅ |
| Listens to wheel events | ❌ | ✅ | ❌ |
| Normalize scroll experience | ✅ | ❌ | ✅ |
| Accessibility | ❌ | ❌ | ✅ |
| CSS Sticky | ❌ | ❌ | ✅ |
| IntersectionObserver | ❌ | ❌ | ✅ |
| Open source | ✅ | ❌ | ✅ |
| Built-in animation system | ✅ | ✅ | ❌ |
| Size (gzip) | 12.33 KB | 26.08 KB | 2.13 KB |
Best Practices & Approaches for Using GSAP with Next.js
When integrating GSAP animations into a Next.js project, it's important to consider the nature of your content and layout. Different scenarios require different approaches to ensure smooth animations and avoid common pitfalls like layout shifts and hydration issues.
Key Takeaway:
- Explore best practices for integrating GSAP animations with Next.js projects.
- Learn when to use different GSAP setup patterns for static, dynamic, and complex layouts.
- Get practical tips to avoid common pitfalls with SSR, hydration, and dynamic content.
Simple static content (no images/dynamic content)
useEffect(() => {
const ctx = gsap.context(() => {
// Your GSAP animations
});
return () => ctx.revert();
}, []);With images/dynamic content (recommended for most cases)
useEffect(() => {
const ctx = gsap.context(() => {
// Your GSAP animations
});
// Refresh after images load
const handleLoad = () => ScrollTrigger.refresh();
window.addEventListener("load", handleLoad);
return () => {
window.removeEventListener("load", handleLoad);
ctx.revert();
};
}, []);Complex layouts / Hydration issues (e.g., Next.js SSR)
useEffect(() => {
let ctx: gsap.Context;
const rafId = requestAnimationFrame(() => {
ctx = gsap.context(() => {
// Your GSAP animations
});
});
return () => {
cancelAnimationFrame(rafId);
ctx?.revert();
};
}, []);Summary - When to use each approach:
| Scenario | Approach |
|---|---|
| Simple static content | Basic gsap.context() |
| Has images | Add window.load + ScrollTrigger.refresh() |
| Layout shift / hydration issues | Add requestAnimationFrame |
| Next.js SSR with complex layouts | requestAnimationFrame + invalidateOnRefresh: true |
| Lazy loaded content | ScrollTrigger.refresh() after content loads |
Key best practices for Next.js + GSAP:
- Always use gsap.context() - For cleanup
- Add invalidateOnRefresh: true - Recalculates on resize/refresh
- Call ScrollTrigger.refresh() - After dynamic content loads
- Use requestAnimationFrame - Only when experiencing timing/layout issues
- Check typeof window !== 'undefined' - For SSR safety (optional with "use client")
The pattern I provided is the safest/most robust for production, for simple demos you can use the basic approach.
Comments (0)