Command Palette

Search for a command to run...

Hectal
Shots in this scene
SHOT 19.1Advanced ~16 min · shot 1 of 6

Interview: Rendering and Performance

In one line

Interviewers ask why transform is cheap, what layout thrashing is and how you would find jank. A strong answer gives the mechanism, a number you measured, an edge case and a trade-off. Here are six model answers checked against this course.

0/6 · 0%

Think of it like this

A driving examiner does not want you to recite the highway code. She asks "why did you check the mirror there?" and listens for a reason. "Transform is faster" is a rule; the follow-up "why, and when is it not?" is where answers fall apart.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

forced layout
The browser must lay the page out in the middle of your script, because you asked for a size right after a change that dirtied the layout.
compositor
The browser part that stacks painted layers and moves, fades or transforms them without the main thread.
long animation frame (LoAF)
A frame over 50 ms. Each entry says which scripts ran and how long they forced layout.
INP
Interaction to Next Paint: how long a click or key press takes to show its result. 200 ms or less is good, over 500 ms is poor.

Step by step

01Run the counter

Run "Count the forced layouts". Six lines print: three list sizes, each done two ways. Thrash reads a row's height and writes the new height, row by row. Batch reads every height, then writes every height.

02Read the sizes

With 0 rows nothing happens. With 1 row there is one read and nothing to force. With 40 rows thrash forces 39 layouts and batch forces none: the first read is free, each later read finds a waiting write.

03Say how it counts

Setting style.height queues a mutation record. The patched offsetHeight getter asks takeRecords(): a non-empty answer means a write is waiting, so the browser must lay out now.

04Say what it cannot see

It only watches offsetHeight. Reading getBoundingClientRect() or scrollTop thrashes just as badly and the counter says 0. Naming a tool's limits is part of a good answer.

Try it yourself

  1. 1

    Make it 200 rows

    Change [0, 1, 40] to [200]. It prints 200 rows, thrash: 200 reads, 199 forced layouts and 200 rows, batch: 200 reads, 0 forced layouts.

Code & diagrams

Count the forced layouts

Nothing moves, so the timeline is empty on purpose: this is about layout. The counter patches `offsetHeight` and asks a mutation observer whether a style write is waiting.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

0 rows, thrash: 0 reads, 0 forced layouts
0 rows, batch: 0 reads, 0 forced layouts
1 rows, thrash: 1 reads, 0 forced layouts
1 rows, batch: 1 reads, 0 forced layouts
40 rows, thrash: 40 reads, 39 forced layouts
40 rows, batch: 40 reads, 0 forced layouts

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Read with getBoundingClientRect instead

In thrash, replace row.offsetHeight + 2 with row.getBoundingClientRect().height + 2.

terminal
$ Run the example
── what you'll see ──
40 rows, thrash: 0 reads, 0 forced layouts
Real output. The page really forces 39 layouts; the counter cannot see them.

Myth vs fact

Myth

Animating transform is always cheap.

Fact

It is cheap when CSS or the Web Animations API hands it to the compositor. A requestAnimationFrame loop that sets style.transform runs on the main thread, and a long task freezes it.

Remember this

  1. 1

    The problem this solves: most candidates know the slogans ("animate transform and opacity"). Few can say what the browser does, give a number, or name the case where the slogan is wrong. Interviewers keep asking until they find that edge.

  2. 2

    The shape of a good answer. Four moves, about a minute: claim (one sentence), mechanism (what the browser really does), evidence (a number you measured or a tool you would use), then edge and trade-off. Every number below comes from a run in this course (Topics 1.4 and 6.1 to 6.6).

  3. 3

    Say what you measured, and where. Topic 6.2's table was recorded in Chromium 153, headless, with software rendering: transform, opacity, background-color, clip-path and backdrop-filter only composite; color, box-shadow, border-radius and filter also paint; width, height, top, margin and font-size also lay out. "In my measurements, and I would re-measure on a phone" separates you from slogan answers.

  4. 4

    Count, do not time. Timings differ on every machine; a count does not. The example below counts layout reads that arrive while a style write is waiting: 40 rows give 39 forced layouts when you alternate and 0 when you batch.

  5. 5

    Know who drives the animation. A transform animation in CSS or the Web Animations API can run on the compositor, so a busy main thread does not stop it. The same transform set from a requestAnimationFrame loop is main-thread work every frame. The property does not decide it.

Explain it without notes

01

What is the difference between a repaint and a reflow, and which properties cause each?

02

Why is transform cheap, and when is it not?

03

What is layout thrashing, how do you find it and how do you fix it?

04

requestAnimationFrame or setTimeout for an animation loop?

05

What do LoAF and INP measure?

06

An animation is smooth on your laptop and janky on a cheap phone. What do you do?

Practice

01

A scroll handler reads el.offsetTop and sets el.style.transform for each of 300 cards. Rewrite it.

02

A trace shows a 90 ms Layout block with a red triangle inside onResize. What do you check first?

Done when you can

  • You can answer with claim, mechanism, evidence and edge

  • You can say which properties composite, paint or lay out, and that you measured it

  • You can explain forced layout with a count, and fix it

  • You can say why a requestAnimationFrame transform is not compositor-driven