Layout, Paint & Composite
layout, paint & composite layout, paint, and composite transform styled dom into frames. the chrome team d layout, paint, and
Introduction
Layout, paint, and composite are the geometry-to-pixels stages. Layout (reflow) computes positions and sizes; paint records draw operations into display lists; composite assembles GPU layers and submits frames. Blink LayoutNG, Skia rasterization, and the Viz compositor implement this pipeline in Chrome.
The Chrome team separates layout-triggering properties (width, height, top) from composite-only properties (transform, opacity) — a distinction that defines modern animation performance strategy on web.dev.
Business problem
Business pressure: Product pages with sticky headers, image carousels, and dynamic pricing animate properties that trigger full layout every frame — scroll feels broken on mid-tier Android, INP fails CrUX thresholds, and support tickets spike during sales events.
- Conversion: Janky scroll on product gallery correlates with lower add-to-cart on mobile field data.
- Compliance: Sticky focus outlines must paint correctly — outline changes can trigger unexpected repaints.
- SEO: Slow render indirectly hurts rankings via CrUX; Google does not measure layout directly but INP/LCP/CLS capture symptoms.
Why this feature exists
Platform motivation: Early browsers repainted entire pages on any change. Layered compositing enabled partial updates and GPU-accelerated scrolling — essential for mobile 60fps and battery life.
- History: Layout engines evolved from block flow → flex/grid → LayoutNG (Blink rewrite for predictable performance).
- Alternative rejected: Full-page bitmap refresh per change — CPU and bandwidth prohibitive on mobile.
- Modern role: Composite thread handles most scroll; main thread layout still dominates dynamic content sites.
Browser internals
Inside the engine: Layout computes fragment tree geometry (LayoutNG in Blink). Paint walks visible fragments, building DisplayItemList. Composite assigns layers (Layerize), rasterizes tiles on worker threads, GPU process draws quads. Invalidation tries to limit layout to dirty subtrees and paint to damage rects.
- Blink LayoutNG: Fragment-based layout; clear separation of layout input/output for caching.
- Paint: Skia records ops; some effects (filters, masks) force layer promotion.
- Composite (cc/Viz): Layer tree with scroll containers; property trees for efficient updates.
- WebKit: Tile-based compositor; aggressive layer squashing on iOS for memory.
- Gecko: WebRender path moves more paint to GPU; fallback to traditional paint.
Layout (geometry)→ fragment tree with x,y,width,heightPaint (display list)→ DrawText, DrawRect, DrawImage opsLayerize→ compositor layers (scroll, fixed, promoted)Raster + Composite→ GPU textures → screen
Rendering workflow
Rendering path: Style change may skip layout if geometry-independent. Layout change invalidates paint for affected regions. Composite may proceed without main-thread paint if only compositor properties changed on existing layers.
- Critical path: First layout + paint of LCP element must complete before LCP timestamp.
- Layout: Flex/grid gap changes, font load, image load without dimensions all trigger.
- Paint: box-shadow, border-radius, text anti-aliasing — costly on large areas.
- Composite: Scroll often compositor-only if layers pre-built.
Feature deep dive
Layout triggers include geometric property changes, DOM structure changes, font load, viewport resize. Paint triggers include visual non-geometric changes. Composite-only updates use transform/opacity on promoted layers.
- Forced sync layout: JS read after write forces immediate layout — DevTools marks "Forced reflow".
- Stacking contexts: z-index, opacity < 1, transform create layers affecting paint order.
- will-change: Hints promotion — overuse increases GPU memory (Chrome team warns on web.dev).
- view transitions: API captures snapshot layers — advanced compositor path.
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Layout vs Composite</title><style>.box { width: 80px; height: 80px; background: #ea4335; margin: 2rem; }.layout-anim { animation: slide-margin 2s infinite alternate; }.composite-anim { animation: slide-transform 2s infinite alternate; }@keyframes slide-margin { from { margin-left: 0; } to { margin-left: 200px; } }@keyframes slide-transform { from { transform: translateX(0); } to { transform: translateX(200px); } }</style></head><body><h1>Layout vs Compositor Animation</h1><p>Profile both boxes in Performance panel.</p><div class="box layout-anim" aria-label="Margin animation"></div><div class="box composite-anim" aria-label="Transform animation"></div></body></html>
Accessibility analysis
A11y architecture: Magnification and high-contrast modes may force additional paints. Focus ring painting must remain visible — outline-offset changes trigger paint invalidation.
- Screen readers: Unaffected by paint/composite — consume AX tree from earlier stage.
- Keyboard: :focus-visible styles trigger paint on focus change — keep selectors cheap.
- WCAG: Motion from compositor animations still subject to prefers-reduced-motion.
SEO impact
SEO architecture: Layout/paint do not change indexed text but affect whether content is visually present at LCP measurement. Lazy-loaded images below fold should not steal LCP if hero is optimized.
- Crawl: WRS waits for layout-stable render for screenshot and extraction heuristics.
- Rich results: Price visible after client layout must match schema at measure time.
- Core Web Vitals: CLS measured at layout shifts during page lifetime — composite does not fix unsized media.
Security considerations
Security boundary: Timing side channels via layout (history sniffing via scroll width) largely mitigated. CSS exfiltration uses layout-adjacent attribute selectors — style layer concern.
- XSS: Injected content changing layout can overlay legitimate UI — visual phishing.
- CSP: Does not affect layout/paint pipeline directly.
- Clickjacking: Composite stacking order places attacker iframe above victim clicks.
Performance impact
Performance: Chrome DevTools Performance labels Layout, Paint, Composite Layers. Long frames >16ms miss 60fps budget. web.dev recommends compositor-friendly properties for animations.
- LCP: Delayed by layout until hero dimensions known + paint completes.
- INP: Input handler triggering layout before paint blocks next frame presentation.
- CLS: Layout without reserved space shifts composite output — score accumulates.
Real production example
Production pattern: Airbnb list cards use transform for hover lift (composite) not margin change (layout). Measured 60fps scroll on mid-tier devices in RUM — pattern cited in Chrome Dev Summit performance talks.
- Pattern: Animate transform + opacity; avoid width/height/top/left in @keyframes.
- Monitoring: Layout instability API + CLS in field data.
- Fix: width/height attributes on img eliminate layout shift at decode.
Enterprise usage
Enterprise: Data grid components virtualize rows to cap layout cost. Fixed row heights enable predictable layout cache hits in Blink.
- Design system: Animation tokens restricted to compositor-safe properties.
- CMS: Image dimensions required fields — enforced at publish for CLS budget.
- CI gates: Lighthouse CLS + filmstrip on key templates.
Common production failures
What breaks in prod: Sticky ad banner injected without reserved slot — layout reflow pushed checkout button below fold, CLS 0.45, CrUX failed for 2 months.
- Incident: box-shadow on scroll listener repainted full viewport each pixel — battery drain reports on iOS.
- SEO regression: Lazy LCP image loaded after layout — LCP 5.1s p75 mobile CrUX.
- Perf regression: Changed carousel from translateX to margin-left — main thread layout every frame.
Architecture review questions
- Which animations on our site trigger Layout in Performance panel?
- Are all LCP candidates sized before image bytes arrive?
- Does scroll hit compositor thread or main-thread paint on our catalog page?
- What is our CLS budget per template and worst CrUX URL?
- Are we over-using will-change causing GPU memory pressure on low-end devices?
- Do interaction handlers read layout properties after DOM writes?
Hands-on project
Project: Animate a box with (A) margin-left and (B) transform:translateX. Record Performance panel — compare Layout/Paint bars. Document finding per web.dev compositor guidance.
- Deliverable: Side-by-side traces + recommended animation CSS for design system.
- Verify: Rendering → Paint flashing green; FPS meter during animation.
- Stretch: Enable prefer-reduced-motion fallback.
Interview questions
Walk through layout → paint → composite with a concrete example.(Advanced)
Changing width triggers layout recalc for subtree, invalidates paint, updates layer bounds, recomposites. Changing transform on promoted layer skips layout/paint on main thread — compositor updates transform matrix and GPU redraws quads.
Follow-up: What promotes a layer?
What causes forced synchronous layout?(Advanced)
JavaScript reads geometric property (getBoundingClientRect, offsetWidth) after invalidating write. Engine must flush pending layout to return accurate value. Fix: batch reads in rAF separate from writes.
Follow-up: List common forcing APIs.
How is CLS related to layout vs composite?(Intermediate)
CLS measures unexpected layout position changes between frames — layout stage. Compositing alone does not fix shifts from unsized images or dynamic ad insertion. Reserve space in HTML/CSS at layout time.
Follow-up: What shifts are excluded from CLS?
Try it yourself
Edit the HTML, CSS, or JS panels — the preview updates as you type.
Try it yourself
Summary
Layout, paint, and composite transform styled DOM into frames. The Chrome team documents compositor-friendly patterns on web.dev — staff engineers profile each stage in DevTools and align animations with GPU-capable properties.