What box an element generates
The display property is the single most important layout switch in CSS: it
decides whether an element is a block or inline box and which layout model
(flow, flex, grid, table) governs its children. Modern CSS reframes
every value as an outer plus inner display type, which makes the once-mysterious
keywords much clearer. This reference lists the common values with their
outer/inner types and a resolver that expands each legacy keyword.
How it works
A legacy single keyword maps to an outer + inner pair:
display: block; /* = block flow */
display: inline-block; /* = inline flow-root */
display: flex; /* = block flex */
display: inline-grid; /* = inline grid */
The outer type (block or inline) sets how the box itself flows among its
siblings; the inner type sets the formatting context for its children.
flow-root is special: it establishes a new block formatting context, which is
why inline-block (inline flow-root) sizes like a block. The box-generation
values stand apart: list-item adds a ::marker, contents makes the box
itself disappear while keeping its children, and none removes the whole subtree
from layout and the accessibility tree.
Choosing the right value
| Goal | Value | Why |
|---|---|---|
| Stack elements vertically, full width | block | Block outer type occupies its own line |
| Flow inline with text | inline | Inline outer type; width/height ignored |
| Inline but sizeable | inline-block | Inline outer, flow-root inner; accepts dimensions |
| Lay out children in a row or column | flex | Block outer, flex inner |
| Inline flex (like a button) | inline-flex | Inline outer, flex inner |
| Two-dimensional grid of children | grid | Block outer, grid inner |
| Remove from layout entirely | none | Generates no box; removes from a11y tree |
| Contain floats without clearfix | flow-root | Creates a new block formatting context |
| Unwrap a wrapper for flex/grid children | contents | Box disappears; children promoted |
Practical notes on less obvious values
display: contents is occasionally misunderstood. It does not make an element invisible — it makes the element itself generate no box at all, as if it were replaced by its children in the DOM. This is useful when you have a semantic wrapper (<ul>, <section>) that breaks a flex or grid layout because it sits between the container and the items you want to distribute. However, removing the box also removes the element from the browser’s accessibility tree, which can hide content from screen readers or break landmark navigation. Use it only when the element carries no meaningful semantics.
display: none differs from visibility: hidden in two important ways. First, a none element takes no space — removing it does not leave a gap. Second, it removes the entire subtree from the accessibility tree, whereas visibility: hidden keeps the element in the tree (inaccessible but present). Use none for genuinely hidden content and visibility: hidden when you want to preserve layout space.
flow-root is underused. It solves the classic float-containment problem without needing a clearfix hack — any block element can gain display: flow-root to contain its floated children. It also prevents margin collapse between the element and its children.
Tips and notes
display: flex/gridonly changes the children’s layout, not the element’s outer flow.- Use
flow-root(orinline-block) to contain floats without an empty clearfix element. contentsis powerful for unwrapping, but audit accessibility — it drops the box from the a11y tree.none≠visibility: hidden:noneremoves space,hiddenkeeps it.