Logo Silhouette
Logo Fill
Hanzla Masood Logo
FRONTEND ARCHITECTURE 8 MIN READ • AUG 14, 2026

How to Build Smooth 60 FPS Scroll

Use GSAP and Lenis to create smooth scroll effects without lag in modern web apps.

HM
Hanzla Masood Software Developer

How to Build Smooth 60 FPS Scroll

This is a mid-length guide for developers who want smooth scrolling and animation without jank. The target is simple: animations should feel stable on normal laptops and high refresh displays.

Why scroll effects become laggy

Most lag comes from doing too much work on each scroll event:

  • reading layout repeatedly
  • writing layout repeatedly
  • animating width/height/top/left every frame
  • large paint-heavy effects

When this happens, frames drop and interaction feels heavy.

The core rules

Follow these rules first:

  1. Animate transform and opacity when possible.
  2. Avoid layout-triggering properties inside frequent loops.
  3. Keep DOM updates small and targeted.
  4. Use one timing source for animation state.
  5. Respect reduced-motion preferences.

These five rules solve most performance issues.

A practical stack: Lenis + GSAP

Use Lenis to normalize scroll behavior and GSAP for animation timelines.

  • Lenis: smooths wheel/touch movement.
  • GSAP: manages interpolation and easing cleanly.

This combo gives good control while keeping code maintainable.

Progress-based animation model

Do not animate directly from raw pixel values every time. Convert scroll into a normalized progress value:

const maxScroll = window.innerHeight * 0.45;
const progress = Math.max(0, Math.min(1, scrollY / maxScroll));

Then map that 0..1 progress into style transitions. This makes behavior predictable across screen sizes.

Avoid layout thrashing

Bad pattern:

window.addEventListener("scroll", () => {
  element.style.width = `${100 - window.scrollY * 0.1}%`;
});

Better pattern:

const x = startX + (endX - startX) * progress;
gsap.to(element, { x, duration: 0.2, overwrite: "auto" });

This keeps animation mostly in compositor-friendly properties.

Use will-change carefully

will-change can help, but overusing it wastes memory. Add it only on frequently animated elements, and remove it when no longer needed.

Good targets:

  • hero container
  • floating nav
  • cursor glow

Bad targets:

  • every card
  • large static sections

Keep visual effects light

Expensive effects can kill FPS, especially on mobile:

  • multiple full-screen blurs
  • many infinite shadows
  • too many particles

Use lightweight alternatives:

  • lower blur radius
  • static gradients
  • fewer animated layers

IntersectionObserver for reveal animations

Reveal items only when they enter viewport. This reduces startup cost and prevents animating hidden content.

Typical flow:

  1. Set initial hidden state once.
  2. Observe cards/sections.
  3. Animate when intersecting.
  4. Unobserve after first reveal.

This pattern is both smooth and simple.

Mobile and accessibility guards

Always include:

  • @media (max-width: ...) simplifications
  • @media (prefers-reduced-motion: reduce) fallback

If user prefers reduced motion, disable non-essential animations. This is both accessibility and performance best practice.

Suggested debugging checklist

When scroll feels slow:

  1. Check if layout properties are animated every frame.
  2. Inspect heavy shadows/filters.
  3. Reduce animated element count.
  4. Verify no duplicate event listeners.
  5. Profile long tasks in browser devtools.

Fix one variable at a time and re-test.

Production baseline

Before release, test:

  • desktop (60Hz and high refresh)
  • Android mid-range device
  • iOS Safari
  • long page with many cards

Also check battery behavior and heat on mobile.

Final notes

Smooth scrolling is not about adding more animation. It is about controlled animation. Use normalized progress, animate cheap properties, and keep effects focused.

Related reading:

Measure before you optimise

Use the browser performance panel to record an actual scroll sequence. Look for long tasks, repeated style recalculation, image decoding, and paint-heavy layers. Do not assume that the animation library is the problem: a large image, a third-party widget, or an unthrottled resize handler can interrupt an otherwise efficient timeline.

Set a performance budget for the experience. For example, limit the number of simultaneously animated layers and make mobile effects simpler than desktop effects. Re-test after deploying production assets, because development builds rarely reveal the same network and decoding costs. Smooth motion is a product requirement that needs measurement, not just visual taste.

A final implementation check

Before release, write down the expected behaviour for a slow connection, a rejected request, and a refresh during an in-progress action. Then test those cases on a real phone as well as a desktop browser. Keep the visible state, the server response, and the log entry connected by one identifier. This small check catches the gaps that polished demos usually hide: stale information, duplicate actions, unclear loading feedback, and recovery paths that work only on a developer machine. Document the decision, keep the interface honest about pending work, and review the result after the first real users interact with it. Reliable software is usually the result of these deliberate, repeatable details rather than one large technical feature.

For scroll work specifically, record one baseline before changes and compare frame pacing after each adjustment. A smoother average frame rate is useful, but stable frame timing matters just as much: occasional long frames are what users feel as jank. Keep that comparison in the project notes so future visual changes do not quietly undo the performance work.

Let's Collaborate ✳

Open for freelance projects & professional consulting.