THN Interview Prep

Rendering pipeline & compositing

Rendering is how code becomes pixels. Senior frontend engineers do not stop at “the page is janky”; they can identify whether time is going into script, style recalculation, layout, paint, compositing, image decode, or GPU memory pressure.

Core details

Ordered pipeline: parse HTML/CSS → DOM/CSSOM → style recalculation → layout → paint → composite.

StageWorkTypical trigger
ParseConvert HTML/CSS bytes into DOM/CSSOMNavigation, streamed HTML, new stylesheet
StyleMatch selectors and compute valuesClass changes, stylesheet changes, custom property changes
LayoutCalculate box geometryDOM structure, size-affecting CSS, font changes
PaintRasterize text, backgrounds, borders, shadows, imagesVisual changes that affect pixels
CompositeMerge layers into a final frameTransform/opacity animation, layer promotion

Browser rendering pipeline showing DOM and CSSOM feeding style, layout, paint, compositing, a forced synchronous layout loop, and a composite-only animation path.

Tree vocabulary: DOM and CSSOM feed the render tree. Layout computes geometry. The browser may build a layer tree for independently composited surfaces.

Forced synchronous layout: if JavaScript writes layout-affecting styles and then reads geometry (getBoundingClientRect, offsetWidth, scrollTop) in the same loop, the browser may flush layout immediately to answer truthfully.

Layer promotion: transforms and opacity can often animate without repainting, but promoted layers consume GPU memory. will-change is a temporary hint, not a blanket optimization.

Diagnostics: use the Performance panel to separate scripting, style, layout, paint, and composite work. Use the Layers panel to verify actual promotion. Use screenshots/filmstrip to connect traces to user-visible symptoms.

Understanding

The browser batches work lazily until it must present a frame or answer a geometry question. Layout thrash breaks that batching by forcing the browser to make the world consistent during JavaScript execution.

Layout cost scales with the number of impacted boxes and the complexity of constraints. Paint cost scales with invalidated pixels and expensive effects such as filters, shadows, masks, and large backgrounds. Style recalculation grows with selector matching and dependency invalidation.

Compositing is a different kind of optimization. Moving an element to its own layer may avoid repainting during transform animation, but too many layers increase memory, upload cost, and mobile instability. A staff answer includes the rollback condition: remove promotion if it does not improve measured frames.

Practical examples

Batch reads and writes:

const rects = cards.map((card) => card.getBoundingClientRect());

requestAnimationFrame(() => {
  rects.forEach((rect, index) => {
    overlays[index].style.transform = `translate(${rect.left}px, ${rect.top}px)`;
  });
});

Choose properties by pipeline cost:

GoalPreferBe careful with
Move element visuallytransformtop, left, changing layout flow
Fade elementopacityanimating visibility without state semantics
Expand contentreserved space, transform, or measured transitionheight animation over large subtrees
Hide offscreen contentvirtualization, content-visibility when appropriatekeeping thousands of nodes live

Senior understanding

ProbeStrong answer
Janky scrollSeparate input handler cost, layout, paint, and compositing in a trace
“Use will-change?”Explain temporary promotion, memory cost, and measurement
CSS-in-JS debateDiscuss critical CSS, runtime style insertion, and invalidation hotspots
CLS regressionTie image/font/DOM mutations to layout stability, not just JS CPU

Failure modes

  • Reading layout after every DOM write in a loop.
  • Animating layout-affecting properties on many nodes.
  • Promoting many elements and causing GPU memory pressure.
  • Loading fonts without fallback metrics, causing text reflow.
  • Debugging React renders while the real issue is browser layout or paint.

Interview drill

Question: "A page scrolls smoothly on desktop but janks on mid-range Android. How do you debug it?"

Model answer structure:

  1. Reproduce with CPU/network throttling and record a Performance trace around the scroll.
  2. Separate scripting, style recalculation, layout, paint, and composite time.
  3. Check whether handlers block scrolling, layout is forced by read/write loops, or paint areas are too large.
  4. Apply the smallest measured fix: passive listeners, virtualization, read/write batching, cheaper paint effects, or limited layer promotion.
  5. Re-test the same trace and define a rollback condition if memory or paint gets worse.

Follow-ups to expect:

  • "Why can transform be faster than top or left?"
  • "When does will-change make performance worse?"
  • "How would you prove the issue is paint rather than React rendering?"

Diagram

Loading diagram…

See also

Mark this page when you finish learning it.

Spotted something unclear or wrong on this page?

On this page