The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Block flow container.panel { display: block flow; }View examples
Inline formatting root.badge { display: inline flow-root; }View examples
Compatible inline block.badge { display: inline-block; }View examples
Explicit block formatting context.group { display: flow-root; }View examples
Contain floated media.card { display: flow-root; } .card img { float: inline-start;; }View examples
Stop child margin collapse.section { display: flow-root; }View examples
Remove only the principal box.wrapper { display: contents; }View examples
Expose children to a grid.grid-group { display: contents; }View examples
Layer a structural fallback.group { display: block; } @supports (display: contents) { .group { display: contents; }; }View examples
Remove subtree from layout.is-removed { display: none; }View examples
Use semantic hidden state[hidden] { display: none; }View examples
Keep text for assistive tech.sr-only { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); }View examples
Generate a marker box.step { display: list-item; list-style-position: inside; }View examples
Use table-internal display.cell { display: table-cell; vertical-align: middle; }View examples
Expect flex item blockification.row { display: flex; } .row > span { display: inline; }View examples
Inspect computed displaygetComputedStyle(node).displayView examples
Keep focus on a generated box.wrapper:focus-visible { outline: 3px solid CanvasText; }View examples
Restore boxes for print@media print { .screen-contents { display: block; } }View examples

The display property controls whether an element generates a box, how that box participates in its parent, and which formatting model lays out its children. This guide separates those decisions, shows why flow-root is the explicit block-formatting-context tool, and treats contents as a narrowly scoped box-tree operation whose accessibility behavior still demands real-device testing.

Step by step

Detailed examples

01

Separate outer participation from inner layout

Two-keyword display syntax makes the model explicit: the outer value says how the principal box participates in its parent, while the inner value selects flow, flow-root, flex, grid, table, or ruby layout for children. Legacy values such as inline-block map to defined pairs and remain useful fallbacks. Replaced elements and layout-internal roles have additional rules, so changing display alone does not turn arbitrary markup into a semantically correct table or control.

Equivalent modern and legacy inline containers
.status {
  display: inline-block;
  display: inline flow-root;
  padding-inline: 0.6rem;
}
Back to quick reference ↑
02

Establish a block formatting context deliberately

flow-root generates a block-level block container and always establishes a new block formatting context. It encloses floats, separates its contents from outside floats, and prevents block margins from collapsing through its boundary. Unlike overflow: hidden, it does not clip intentional shadows, focus rings, or positioned decoration. A BFC is not containment: it does not provide the performance or sizing guarantees of contain.

Float media without a clearfix pseudo-element
<article class="card">
  <img src="avatar.png" alt="Samira Chen">
  <h2>Samira Chen</h2>
  <p>Maintains the release checklist.</p>
</article>
Let the article enclose the float
.card { display: flow-root; }
.card img { float: inline-start; margin-inline-end: 1rem; inline-size: 5rem; }
Back to quick reference ↑
03

Remove a box, not your document structure

display: contents normally prevents the element itself from generating boxes and promotes its child boxes for layout. The DOM node, selectors, inheritance, and event propagation still exist. Pseudo-elements can generate boxes as children. Unusual elements have special rules, and historical accessibility implementations have incorrectly removed semantics, so do not use contents casually on meaningful landmarks, lists, tables, labels, or interactive elements. Test the browser and assistive-technology combinations you support.

Flatten a decorative grid grouping only
.dashboard { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.decorative-group { display: contents; }
@supports not (display: contents) { .decorative-group { grid-column: 1 / -1; } }
Back to quick reference ↑
04

Choose absence, invisibility, or clipping intentionally

display:none suppresses the whole subtree from layout and, in ordinary cases, from accessibility APIs; it is appropriate for content that is genuinely inactive. visibility:hidden preserves layout space but also makes the subtree non-interactive. opacity:0 merely makes pixels transparent and can leave focusable controls active. A visually-hidden utility uses clipping when text must remain available as an accessible name; verify it at high zoom and in forced-colors mode.

Hidden state and robust label utility
[hidden] { display: none !important; }
.sr-only {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}
Back to quick reference ↑
05

Respect layout-internal roles and semantics

list-item adds a marker box and can be combined with an outer and inner display type. Table-internal values participate in fix-up rules that may generate anonymous wrapper boxes. They describe visual formatting, not document relationships: a div displayed as table-cell is not exposed as a table cell to assistive technology. Start with ol, ul, table, th, and td when those meanings apply, then use CSS to control their presentation.

Preserve an ordered list while styling markers
.steps { padding-inline-start: 1.5rem; }
.steps > li { display: list-item; }
.steps > li::marker { color: #1d4ed8; font-weight: 800; }
Back to quick reference ↑
06

Account for blockification and generated boxes

Flex and grid containers blockify the outer display type of in-flow children; absolutely positioned and floated boxes are blockified too. This affects computed values without changing DOM semantics. display also controls whether ::before and ::after can generate boxes. Inspect computed styles when debugging, but reason about the formatting context and box tree rather than expecting the authored token to survive unchanged.

Inspect specified behavior after flex blockification
const item = document.querySelector(".row > span");
console.log(getComputedStyle(item).display);
Back to quick reference ↑
07

Test focus, reading order, zoom, and print

CSS visual reordering never changes sequential focus or reading order. Keep DOM order meaningful, retain native interactive elements, and never place keyboard focus on an element whose principal box has been removed by contents. Test at 400% zoom, with keyboard-only navigation, screen readers, forced colors, and printed output. Use @supports only to detect parsing; it cannot certify correct accessibility-tree behavior.

Visible keyboard focus with system colors
:focus-visible { outline: 3px solid CanvasText; outline-offset: 3px; }
@media print { .screen-contents { display: block; } }
Back to quick reference ↑

Local code tester

Compare flow-root and contents

Toggle the checkboxes to contain a float and flatten only the decorative grid group while the document order stays unchanged.

Runs in your browser
Preview

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. CSS Working GroupCSS Display Module Level 3drafts.csswg.org
  2. CSS Working GroupCSS Display Module Level 4drafts.csswg.org
  3. World Wide Web ConsortiumCSS 2.2: Visual formatting modelw3.org
  4. Web Accessibility InitiativeUnderstanding Success Criterion 1.3.1: Info and Relationshipsw3.org
  5. MDN Web Docsdisplaydeveloper.mozilla.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback