"Normal flow is what the browser does when you don't tell it to do anything else. Most layout is just nudging it."
Normal Flow: The Default Behavior
If you put a stack of elements in a page with no positioning, no flex, no grid, the browser arranges them with normal flow:
- Block-level elements stack vertically, each on its own line, taking the full width of their container.
- Inline-level elements sit side by side in lines that flow left-to-right (or right-to-left for RTL languages), wrapping when they hit the container edge.
- The vertical direction is the block axis; the horizontal direction is the inline axis. (These flip in vertical writing modes — Japanese, Mongolian — which is why they're named by axis, not direction.)
Every display value is a recipe that tweaks this default.
The Core display Values
block— block-level: new line, full container width. Default for<div>,<p>,<h1>–<h6>,<section>,<article>,<ul>,<li>, etc.inline— sits in text flow, no new line, ignoreswidth/height/vertical margins. Default for<span>,<a>,<em>,<strong>,<code>.inline-block— sits in text flow (inline) but acceptswidth/height/all margins (block-like internals). Hybrid for inline buttons, badges, custom controls.none— removed from the layout entirely. Not visible, not in flow, not focusable. Different fromvisibility: hidden, which hides the element but keeps its space.flex— turns the element into a flex container; its children are arranged in one direction with alignment controls. (Track 5.)grid— turns the element into a grid container; children placed in rows and columns. (Track 6.)contents— the element itself disappears from the box tree but its children remain. Useful for unwrapping a semantic container without affecting layout.list-item— block-level with a marker (default for<li>). Any element can be turned into a list item.flow-root— block-level that establishes a new block formatting context (BFC). Used to clear floats inside without a clearfix hack, prevent margin collapse with children, contain floats.
Block Formatting Context (BFC)
A BFC is an isolated layout region where margins don't escape, floats are contained, and certain layout rules are bounded. New BFCs are created by:
display: flow-root(the modern, clean way)- Floats themselves
display: inline-blockdisplay: flexorgridoverflow: hidden,auto, orscroll(other thanvisible)position: absoluteorfixedcontain: layoutorpaintorstrict
When you find yourself adding overflow: hidden to stop floats from leaking out of a parent, the modern fix is display: flow-root — it creates the BFC without any side effects.
display: none vs visibility: hidden vs opacity: 0 vs hidden attribute
display: none— gone from the layout. Not visible, not focusable, no space taken, ARIA-hidden by default.visibility: hidden— invisible but still takes up space. Not focusable.opacity: 0— visible (in the tree, in flow, focusable, clickable) but transparent. Use for animations only, never for hiding.- HTML
hiddenattribute — equivalent todisplay: none, but settable from HTML/JS without touching CSS. aria-hidden="true"— hidden from screen readers but visible. Pair with one of the above only if the element should also be visually hidden.
display: none. Hiding visually but keeping screen reader access (a skip link)? Custom "visually-hidden" class with clip-path. Animating out? Don't use display: none — animate opacity and then set display: none on transitionend.Visually Hidden — The Accessibility Standard
Sometimes you want content visible to screen readers but not visually rendered (skip links, hidden labels, button names that the design replaces with an icon). The community-standard pattern:
Inline Whitespace Gaps
If you have <span>A</span> <span>B</span>, the whitespace between them renders as a visible space because inline elements collapse whitespace into a single space. This is why inline-block buttons sometimes have mysterious gaps between them. Fixes: put them on the same line without whitespace, use font-size: 0 on the parent (and reset on children), or switch to flexbox where whitespace doesn't matter.
Pippa's Note
display: flex and display: grid for every layout container. There's not a single float or clearfix hack in the codebase. The classic display: contents trick appears once — in the chat message list, where an <article> wraps two visually-disjoint groups but should not interrupt the flex layout's spacing. Modern display modes solve modern problems.