← Guides

Why GSAP scroll animations jank on phones.

The bug report

"On mobile the scaling of the KODEkid logo hitches near the end of the scroll." That's the whole report. No stack trace, no repro steps beyond "scroll on a phone." The temptation with a report like that is to start tweaking easing curves and timing — the fix ships, it feels a bit better, and you have no idea if you actually solved anything.

Measure before touching anything

The animation in question scales seven letters from their own centres until they cover the screen, at which point a solid colour floods over and closes the gaps. On a 390px-wide phone, the letters were peaking at 16.5× scale — meaning each glyph's rendered box was 776×1238 CSS pixels.

That number alone doesn't say much. Multiply by the device pixel ratio phones actually ship at:

776 × 1238 × 3² (DPR 3) ≈ 8.6 million pixels — per letter, times seven

That's the browser re-rasterising roughly 60 megapixels of glyph outline on every single scrub frame, for a state that — because the animation also fades a solid colour over the screen at the same point — was already invisible by the time it happened. All of that GPU work was spent drawing something nobody could see.

Why this doesn't show up in DevTools CPU throttling

Chrome DevTools' CPU throttling slows down JavaScript execution on the main thread. Raster and compositing happen elsewhere — on the GPU, in a separate process. You can throttle the CPU 20× and still get a perfectly smooth scrub, because the bottleneck was never JavaScript. If your test methodology can't reproduce the bug, it can't tell you when you've fixed it either. Measuring the actual pixel math sidesteps the whole question.

The fix

Once the cause is a number, the fix is a number too:

Verifying it, not just shipping it

The fix isn't real until it's been measured the same way the bug was: before/after peak-scale numbers, and — because performance fixes have a habit of quietly breaking correctness — a full reverse-scroll check confirming the element still returns to exactly its starting state when you scroll back up. A performance fix that leaves the animation unable to reverse cleanly has traded one bug for another.

Written by Lars Sohl

Frequently asked questions

Why does a scroll animation jank on mobile but not desktop?
Usually not JavaScript — it's raster cost. Scaling an element up makes the browser redraw its pixels at the new size on every frame, and that cost grows with the square of the scale. A phone's higher pixel density (DPR 2-3) multiplies it further. Desktop GPUs and lower DPR hide the same underlying cost.
How do you actually measure GPU/raster cost in a browser?
Compute it directly: element width times height times device pixel ratio squared gives the megapixel count being rasterised. Compare that across breakpoints before touching any code — it turns a vague 'feels janky' into a concrete number you can cut.
Does CPU throttling in Chrome DevTools reproduce raster jank?
No. DevTools' CPU throttling slows main-thread JavaScript, not compositor/raster work. A scroll animation that's slow because of raster cost can look perfectly smooth under CPU throttling and still jank on a real phone — measure the actual pixel math instead.

ENDA