Skip to content
Performance

The 60fps handshake: what devtools is really telling you

A frame budget is a contract between the compositor and your paint calls. Learn to read the performance trace the way a negotiator reads a room — and stop guessing which property broke it.

Answers Why does my animation feel janky on a phone but smooth on my laptop?frame budget, not frame rate, is the number that decides it — and the motes ship a low-end tier.

Advanced2 min read (computed · recorded 10)updated 2026-09-09performance60fpsdevtoolscompositorcss

The budget, in human terms

  • At 60fps one frame lasts 16.7ms — and the browser keeps ~6ms for itself. Your script, layout and paint get roughly 10ms.
  • A dropped frame isn't the crime; a dropped frame every third scroll is. DevTools paints each over-budget frame red in the FPS graph — look for rhythm, not single spikes.
  • Long tasks block input too: a 120ms main-thread task means taps and scrolls queue behind it. Same fix, harsher deadline.

Read the three lanes

Open Performance → record a scroll. You'll see a main-thread lane (purple scripting, green layout, pink paint) and a compositor lane below. The handshake: every time you animate a property the main thread owns — width, height, top, left, box-shadow — the main thread must re-run layout or paint before the compositor can show anything.

If your frame is red in the compositor lane alone, the browser is struggling to rasterise and upload tiles — usually too many backdrop-blurs or giant repaint regions, not your JavaScript.

The transform/opacity-only rule, quantified

trace-reading.js
// red flags in a scroll trace, in order of cost:
// 1. 'Layout' blocks > 2ms repeating  → animating width/top/height
// 2. 'Paint' blocks growing each frame → backdrop-blur on a moving layer
// 3. 'Rasterize' every frame          → layer bigger than the viewport
// 4. scripting > 8ms in a scroll      → layout-thrash or React re-render
//
// the fix checklist:
//  - move the animated element to its own layer (will-change: transform)
//  - animate only transform / opacity / filter (perf-tier: yes)
//  - replace box-shadow motion with a pre-blurred pseudo-element
//  - once the layer exists, REMOVE will-change — it costs memory

The 8ms habit

Budget in your head

Before writing any animation, ask: which lane does this property live in? If the answer is layout or paint, you've spent the budget before the frame started. transform and opacity are the only properties that skip both — that's not a style preference, it's the compositor's contract.

Practise the lesson

Theory sticks when you ship it. These original Motif assets put this guide's lesson to work — open one and copy it into your own page.