Part 4 · 2 chapters · ~12 min

Layout

From a styled tree to geometry: boxes and the box model, formatting contexts, flex and grid, inline text; then forced layout and thrashing, containment and skipping, and layout shift.

10

Boxes, contexts and text

How a styled tree becomes geometry: boxes, formatting contexts, the layout algorithms and inline text.

Layout (reflow)

styled treelayoutsizes, positionsfragment treegeometry

Computing the size and position of every box from the styled tree; the output is the layout tree with geometry.

in practicePurple "Layout" slices in the Performance panel; the stage most forced-sync bugs trigger.

deep dive: Browser P4

Layout tree

DOMdiv span (display:none) ::before (absent)playout treeblock box (no span) ::before boxblock box

The tree of boxes that actually take space: display:none elements are absent, pseudo-elements are present, anonymous boxes are added.

in practiceWhy display:none removes an element from layout but visibility:hidden keeps its space.

deep dive: Browser P4

Box model

marginborderpaddingcontentwidt…

Every box is content, padding, border and margin; box-sizing decides whether width includes padding and border.

in practicebox-sizing: border-box in every reset; the box diagram in the Computed pane.

deep dive: Browser P4

Formatting context

BFC (root)flex containerflex it…grid containergrid it…each context lays out its own children

An independent layout region (block, inline, flex, grid) whose children are laid out by its rules and do not interact with the outside.

in practicedisplay: flow-root to contain floats; margins not collapsing through a flex container.

deep dive: Browser P4

Margin collapsing

expectedmargin-bottom 24+ margin-top 16= 40px gapactual (block flow)max(24, 16)= 24px gap

Adjacent vertical margins of blocks in normal flow combine into the larger of the two rather than adding.

in practiceA child's margin escaping its parent; gaps that do not add up; flex and grid do not collapse.

deep dive: Browser P4

Flexbox

itemflex: 1itemflex: 2itemflex: 1free space shared 1 : 2 : 1 along the main axis

One-dimensional layout along a main axis with grow, shrink and basis distributing free space among items.

in practiceToolbars, rows of buttons, centring; min-width: 0 to let flex items shrink below their content.

deep dive: Browser P4

CSS Grid

headerheaderheadernavmainmainnavmainmainfooterfooterfooter

Two-dimensional layout of rows and columns, with tracks sized by fr, minmax and auto, and items placed by line or area.

in practicePage shells, dashboards, card grids with auto-fill and minmax (this page's grid).

deep dive: Browser P4

Intrinsic size

min-contentfit-contentmax-contentcontainer220 px

The size an element wants from its content: min-content (narrowest without overflow) and max-content (widest without wrapping).

in practicewidth: fit-content; grid tracks sized auto; text that will not shrink inside a flex row.

deep dive: Browser P4

Containing block

viewportfixe…position: relative ancestorabso…the elementtop/…

The box against which an element's percentage sizes and its position offsets are resolved.

in practiceposition: absolute resolving against the nearest positioned ancestor; transforms and contain creating new containing blocks for fixed elements.

deep dive: Browser P4

Stacking context

root contextheader (z 10)main (transform → new context) modal (z 9999, trapped)only…

A group of elements painted together in z-order; z-index only competes within the same stacking context.

in practiceA modal with z-index 9999 still under a header because its parent has opacity or transform.

deep dive: Browser P5 · Browser P4

Line box and inline layout

line 1: The quick brownline 2: fox jumps [img]tall…line 3: over the dog

Inline content is broken into lines; each line box is as tall as its tallest inline, aligned by baseline.

in practiceMystery gaps under images (they sit on the baseline); line-height on mixed font sizes.

Text shaping

"office"charactersshaperfont + scripto ffi c eligature glyphs

Turning a string and a font into positioned glyphs, handling ligatures, kerning, complex scripts and bidirectional text (HarfBuzz).

in practiceArabic letter joining, Devanagari conjuncts, emoji sequences; why text width cannot be computed by counting characters.

deep dive: Algorithms P9
THE LAYOUT LAYER, IN ORDER
from a styled tree to geometry, and the ways layout goes wrong and gets contained
swipe the figure sideways, or tap expand for full screen
1/6
build boxes
Build boxes: styled elements become a layout tree of boxes, each with the box model, sized against its containing block.
11

The cost of layout, and stability

When layout runs too often, how to contain and skip it, and how to keep content from moving under the user.

Forced synchronous layout

el.classList.add("open"); // write: layout dirtyconst h = el.offsetHeight; // read: layout nowel.style.height = h + "px";// batch reads, then writes

Reading a geometry property (offsetHeight, getBoundingClientRect) after a style write, which makes the browser run layout immediately to answer.

in practiceThe "Forced reflow" warning on a Layout slice in the Performance panel.

deep dive: Browser P4 · DevTools P5

Layout thrashing

writeread → layoutwriteread → layoutwriteread → layout75 msone layout per iteration

Interleaving reads and writes in a loop, forcing a fresh layout on every iteration.

in practiceA list resize loop that takes 300 ms; fixed by reading all, then writing all, or using requestAnimationFrame.

deep dive: Browser P4 · DevTools P5

Layout boundary (containment)

no containmentchange insiderelayout ancestorsand siblingscontain: strictchange insiderelayout onlythe subtree

contain: layout (or size, or strict) tells the engine an element's inside cannot affect outside, so layout work stays within it.

in practiceWidgets and list rows that change often; content-visibility builds on it.

deep dive: Browser P4

content-visibility

visible: laid outvisible: laid outoff-screen: skippedoff-screen: skippedoff-screen: skippedoff-screen: skipped

content-visibility: auto skips layout and paint for off-screen subtrees until they approach the viewport.

in practiceLong documents and feeds rendering faster; contain-intrinsic-size to keep scrollbar stable.

deep dive: Browser P4 · FSD P6

Cumulative Layout Shift

goodneeds workpoor0.1CLS at p75; 0.25 is the poor threshold

The sum (in session windows) of unexpected movement of visible content, weighted by how much moved and how far.

in practiceImages without dimensions, late-loading ads and banners, font swaps; Core Web Vital with a 0.1 threshold.

aspect-ratio

no dimensions0px tallimage loadscontent jumpsaspect-ratio: 16/9space reservedimage loadsno shift

A CSS property reserving a box's height from its width before content loads, so media does not shift layout when it arrives.

in practicewidth and height attributes on img (which set aspect-ratio automatically); video embeds.

deep dive: Browser P4

Viewport units

100svhchrome shown (smallest)100lvhchrome hidden (largest)100dvhtracks it live100vhusually = lvh on mobile

vw, vh and the newer svh, lvh and dvh, sized to the small, large and dynamic viewport as mobile browser chrome shows and hides.

in practice100vh hiding content behind the mobile URL bar; 100dvh as the fix.

deep dive: Browser P4

Scroll anchoring

reading item…item 12 grows+200px abovescroll += 200item 40 stays

The browser keeping the visible content in place when content above it changes size, by adjusting scroll position.

in practiceChat and feeds that do not jump when an image above loads; overflow-anchor: none to opt out.

deep dive: Browser P4

ResizeObserver

layoutResizeObserv…sizes changedcallbackbefore paint

An API that reports element size changes after layout, without polling or forced layouts.

in practiceResponsive components, charts that redraw on container resize, virtualised lists measuring rows.

deep dive: Browser P4

Subpixel layout

3 columns of 100px / 333.328125px eachsnapped at paint33, 33, 34px

Layout computed in fractional pixels (LayoutUnit, 1/64 px) and snapped at paint, so percentages and zoom stay accurate.

in practicegetBoundingClientRect returning 33.328125; 1px seams between tiles at some zoom levels.

deep dive: Browser P4

Virtualisation (windowing)

(not rendered)(not rendered)row 401row 402row 403row 404(not rendered)(not rendered)rows near the viewport only

Rendering only the rows near the viewport and recycling them as you scroll, so a 100,000-row list costs about as much as 30.

in practicereact-window, TanStack Virtual; table views in dashboards and trading blotters.

deep dive: FSD P6 · Algorithms P1

Anchor positioning

.btn { anchor-name: --menu; }.menu { position-anchor: --menu; top: anchor(bottom); left: anchor(left); position-try-fallbacks: flip-block; }

CSS that positions an element relative to another element anywhere in the document (anchor-name, position-anchor), with fallbacks when it would overflow.

in practiceTooltips, menus and popovers without JS positioning libraries.

deep dive: Browser P4