Skip to content
codingncaffeine edited this page Sep 3, 2026 · 34 revisions

Layout

Layout is a pure function of the styled tree and the viewport: styles in, an immutable fragment tree out, in page coordinates. Painting consumes fragments only.

Block and inline

  • Block containers stack their block children; inline content is broken into line boxes with greedy breaking, whitespace collapsing per white-space (normal, nowrap, pre, pre-wrap, pre-line), an emergency break inside a word that cannot fit a line, and text-align.
  • Margins collapse per CSS 2.1 §8.3.1: between siblings, through a parent's open top and bottom edges, and through empty boxes; a cleared box keeps its margin inside, and an empty box holding a float ends the walk.
  • Percentage widths resolve against the containing block; percentage heights (and min-height, max-height) against a definite containing height — a written length, a percentage of a definite height in turn, a flex line's settled size, an absolutely positioned box's containing block, or the viewport for the root — and stay auto without one.
  • min-width, max-width, min-height and max-height hold blocks, floats, flex items and replaced boxes.
  • box-sizing: content-box (the initial value) and border-box, under which a written width, height, min-/max- size or flex basis names the border box — the padding and the borders come off it, and the content floors at zero when they are wider than the size written. A form control is sized whole either way: its own border and padding live inside the size it reports.
  • Lists get their markers (disc, circle, square, decimal, none).

Inline boxes and the line

  • An inline box draws its own background and border and takes room for its margin, padding and border where it opens and where it closes. Broken over several lines it is one box sliced: the line it carries on to draws neither the edge it never reached nor the one it has not come to. Broken around a block it is two complete boxes, each with all four of its edges.
  • A block-level box inside an inline box splits the inline box around it and lays out as a block child of the containing block (CSS 2.1 §9.2.1.1): a card inside a link keeps its border, padding and background.
  • The line box follows CSS 2.1 §10.8: every box on the line reaches above and below the baseline it is aligned to — the strut of the block's font, text by its ascent and descent within its line height, a picture by its height, an inline-block by its own ascent and descent — and the line runs from the uppermost top to the lowermost bottom.
  • vertical-align on inline boxes and atomic boxes alike: baseline, sub, super, text-top, text-bottom, middle, top, bottom, a length, or a percentage of the box's own line height. A run inside nested spans takes the alignment of the nearest raised or lowered inline box around it; top and bottom boxes sit at the line's edges and grow the line when taller.
  • line-height: normal is what the face asks for (its ascent, descent and line gap); a written line height places the baseline by the half-leading model.

Inline-block

display: inline-block, inline-flex and inline-grid (and inline-table until tables land) lay out as one atomic box on the line: shrink-to-fit wide like a float, the margin box what the line holds, sitting on the baseline of its last line box — its bottom margin edge when it has none, and the higher of the two when it clips its overflow, as CSS 2.2 has it. An absolutely positioned inline-block becomes a block with an inline static position.

Floats

  • float: left and float: right, placed at their point in flow — mid-line too — no higher than an earlier float, below what their own clear names, then down until they fit beside the floats at that height.
  • clear on blocks and on <br> (the CSS property or the clear attribute).
  • Auto widths shrink to fit from the min-content and max-content widths of the float's contents.
  • Boxes with their own formatting context (overflow other than visible, display: flow-root, flex containers, inline-blocks, floats themselves) contain their floats and sit beside outside floats — narrowed, or below them when a written width does not fit.
  • Line boxes and formatting-context boxes keep clear of floats along their whole height (CSS 2.1 §9.5), not only at their top: a float starting lower narrows the line, or moves it below the next float when its content no longer fits.

Flexbox

display: flex and inline-flex: the items (element children in order, the container's own text as anonymous items, order sorted), each item's flex base size and automatic minimum, lines (flex-wrap, both directions), flexible lengths (grow into free space or shrink out of overflow, weighted, never below the minimum, with items frozen at their minimum and the rest re-shared), cross sizes, align-items/align-self (stretch, flex-start, flex-end, center; baseline as flex-start for now), align-content across wrapped lines, justify-content (all six values, the reverse directions swapping the ends), row-gap/column-gap/gap, flex-direction in all four directions, and the flex and flex-flow shorthands. A single-line container gives its line the container's cross size; a wrapping container whose items fit one line keeps that line its items' size.

Auto margins on items are zero for now (no margin centering, and no stretch prevention), and baseline alignment is not written.

Grid

display: grid and inline-grid, css-grid-1 without subgrid and masonry:

  • The explicit grid — grid-template-columns and grid-template-rows track lists: lengths and percentages, fr, auto, min-content, max-content, minmax(), fit-content(), repeat() with a count or auto-fill/auto-fit (as many repetitions as fit; auto-fit collapses the empty ones), and line names in brackets; grid-template-areas (each area a rectangle, or the declaration is dropped) with the -start/-end line names it implies; the grid-template and grid shorthands, grid-auto-flow included.

  • Placement — grid-row, grid-column, grid-area and their longhands: line numbers (negative from the end), the nth line with a name, a name alone (its area's edge, else the first so named), span by count or to a named line; lines outside the explicit grid make implicit tracks, sized by grid-auto-rows/grid-auto-columns (the pattern runs forward after the grid and backward before it). Auto-placement (css-grid-1 §8.5) in row or column flow, sparse or dense, in order-modified document order; the container's own text becomes anonymous items, its ::before/::after boxes items placed by their own properties.

  • Track sizing — the algorithm of css-grid-1 §11: base sizes and growth limits from the items' minimum, min-content and max-content contributions (single-track items first, then spanning items by span, then items crossing flexible tracks), the free space maximizing the tracks, fr shares found by the fr-size search, and auto tracks stretched by justify-content/align-content: normal or stretch. Percentage tracks and gaps resolve against the container's content box; under an indefinite height they count as auto while the content height is found, then resolve against it and the rows are sized again.

  • Alignment — justify-content and align-content distribute the free space between the tracks (start, end, center, space-between, space-around, space-evenly, stretch); justify-items/justify-self and align-items/align-self place an item in its area (stretch, start, end, center; normal stretches a block and keeps a picture or control at its own size; baseline is start for now); auto margins take the free space first; place-items, place-self and place-content. A grid item's percentages resolve against its area. z-index on a grid (or flex) item orders it among its container's positioned boxes.

  • Sizing the container — an inline-grid, a float or a flex item that holds a grid shrinks to fit: the columns sized under a min-content and a max-content constraint, gaps included.

  • Absolute positioning (css-grid-2 §9) — an absolutely positioned child of a grid container is not a grid item, but when the container is also its containing block its placement still names a grid area, and that area is the containing block: an offset counts from the area's edge, a box with auto offsets stands at the area's corner and shrinks to fit, and a box stretched between opposite offsets fills the area. A property naming a line the grid does not have counts as auto, and an auto edge stays on the container's padding edge, so one axis can be the area's and the other the padding box's.

Baseline alignment, subgrid and grid-lanes are not written.

Positioning

  • position: relative shifts a box after layout without touching the flow. sticky stays put until scroll containers land.
  • position: absolute and fixed: the box is placed in the nearest positioned ancestor's padding box (or the viewport) by its offsets — width as written, stretched between left and right, else shrink-to-fit in what the offsets leave; height likewise; over-constrained boxes solve their auto margins; a box with no offsets stands at its static position, where it would have been in flow. Replaced boxes keep their own size; the offsets place them without stretching.
  • Painting follows CSS 2.1 Appendix E: a positioned box with a z-index is a stacking context painted as one unit at its level; negative levels go under the context's own flow.

Hiding

visibility: hidden keeps a box's room and paints nothing (a visible descendant paints). opacity: 0 hides a box and everything in it; between zero and one the box paints as if opaque for now. overflow other than visible clips what a box contains to its padding box, positioned descendants included when the box is their containing block.

Transforms

The translations of transform (translate, translateX, translateY, translate3d, added up along a list) and of the translate property move a box after layout, percentages of its own size; any transform makes the box a stacking context. Rotations, scales and skews are passed over, leaving the box where it is.

Replaced boxes

  • Pictures are sized by CSS, by their width/height attributes, or by themselves, the ratio kept; a picture wider than its container shrinks to fit. srcset, sizes and <picture> choose the source for the viewport (see Painting and text).
  • An iframe, canvas, video, embed or object is a box of its own too — 300 by 150 when nothing sizes it, as CSS 2.1 §10.3.2 has it — and none of them show their children.
  • On a line, a replaced box carries its margins, border and padding; the picture sits inside them and the bottom margin edge rests on the baseline.

Form controls

Text fields, password fields, textareas, checkboxes, radio buttons, selects and buttons lay out as atomic boxes on the baseline, sized by their kind (size, cols/rows, the caption, the widest option) or by CSS, with their margins around them; block-level controls stand on their own. See The shell for how they behave.

Tables

CSS 2.1 §17, the separated border model:

  • Structure — every display value of the table model: table, inline-table, the row groups (thead first and tfoot last, wherever they stand), rows, cells with colspan and rowspan (a rowspan of 0 reaches the end of its group), columns and column groups with span, captions (caption-side: top or bottom). The anonymous boxes of §17.2.1 are generated: a run of table parts outside a table gets an anonymous table around it (an inline-table inside inline content), loose content in a table or a row group gets an anonymous row, and loose content in a row an anonymous cell, blank text between parts dropped.
  • Widths — the automatic layout of §17.5.2.2: each column's minimum and maximum from its cells' content and written widths, spanning cells widening the columns they span in proportion, percentage columns taking their share first, written widths holding, the other columns sharing the rest — their maximums when it fits, a point between their minimums and maximums when not. A table's width is what it is written to be (an HTML table's border box; another element's content box), else it shrinks to fit the room; table-layout: fixed takes the widths of the columns and of the first row's cells and shares the rest equally. border-spacing and the table's border and padding count in.
  • Heights — a row is as tall as its tallest cell, the baseline-aligned ones lined up first; a spanning cell that needs more gets it from the last row it spans; a written row or cell height is a floor; a written table height stretches the rows in proportion. Cells sit in their rows by vertical-align (top, middle — the row groups' default — bottom, baseline).
  • Painting — the table's border and background, the column groups' and columns' backgrounds under the rows, the row groups' and rows' under the cells, and each cell's own border and background; the table's baseline is its first row's.
  • Presentational attributes — the HTML rendering section's mappings arrive as author declarations of zero specificity: width, height, bgcolor, align, valign, nowrap on the table parts (and align/bgcolor/text on body, div, p, headings, hr, img with hspace/vspace/border, font with color/size/face), and a table's cellspacing, cellpadding and border, the last two reaching its cells.

The collapsing border model (border-collapse: collapse, CSS 2.1 §17.6.2) lays out with no gutters and no table padding, and the borders merge. At every segment of every grid line the table, its column groups, columns, row groups, rows and cells all offer a border, and §17.6.2.1 picks one: a hidden border takes the line away outright, none loses to everything, otherwise the widest wins and equal widths go to the box that comes first in the list cell, row, row group, column, column group, table. The winner runs down the middle of the line and the boxes on either side each keep half of it, so the shared line is drawn once at its full width; a box that spans takes the widest segment along each of its edges, and the table box keeps the outer half of its outermost lines. empty-cells: hide and visibility: collapse on rows and columns are not written.

Reading the layout

sashfold --render page.html -o out.png --dump-layout

prints every fragment — tag, id and class, position, size, baseline, and flags for floats, positioned boxes and stacking contexts — and every text run with its position, baseline and width.

Clone this wiki locally