What CSS display really controls

The display property is basically CSS’s “how should this element behave in the layout?” switch. It controls two big things:

  • Outer display — how the element itself participates in the page flow (does it start on a new line? does it flow with text?)
  • Inner display — how the element lays out its children (normal flow vs flex vs grid, etc.)

That’s why values like block and inline feel like “outer behavior”, while values like flex and grid are mostly about “inner behavior” (they create a layout system for children).

In this tutorial, you’ll see that display can change:

  • Whether an element starts on a new line
  • Whether width / height apply
  • How children are arranged and aligned
  • Whether the element exists in layout at all (none)
 .demo { display: block; } 
 .demo { display: inline; } 
 .demo { display: inline-block; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: ui-monospace, SFMono-Regular, monospace;
}

.row {
border: 2px dashed #bbb;
padding: 12px;
}

.demo {
width: 220px;
height: 70px;
padding: 10px;
border: 3px solid #111;
background: #f2f2f2;
}

.note {
margin-top: 10px;
font-family: system-ui, Arial, sans-serif;
font-size: 14px;
color: #333;
}
 
Before I am the .demo element After

Try the snippets: block forces a line break, inline flows with text, inline-block flows with text but keeps width/height.

display: block (the default “big box”)

A block element usually:

  • Starts on a new line
  • Tries to stretch to the full width of its container (unless you set a width)
  • Respects width, height, margin, and padding normally

Common block elements are div, p, h2, section, etc.

 .card { display: block; width: 260px; } 
 .card { display: block; width: 100%; } 
 .card { display: block; width: fit-content; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
font-size: 12px;
}

.stage {
border: 2px dashed #bbb;
padding: 12px;
max-width: 520px;
}

.card {
border: 3px solid #111;
background: #f2f2f2;
padding: 12px;
font-family: ui-monospace, SFMono-Regular, monospace;
}
 
I am a block element. My width depends on the snippet.

Learn more about display: block in the CSS Display Block Interactive Tutorial.

display: inline (text-flow mode)

Inline elements flow with surrounding text, like words inside a paragraph. Think span, strong, em, and a.

The biggest beginner gotcha: width and height don’t apply the same way to inline elements. Inline elements usually size to their content.

  • width and height won’t “stretch” an inline element
  • Horizontal padding works nicely
  • Vertical padding can visually grow the background, but it doesn’t push lines apart in a predictable “boxy” way
 .tag { display: inline; width: 220px; height: 60px; } 
 .tag { display: inline; padding: 6px 12px; } 
 .tag { display: inline; padding: 16px 12px; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}

p {
max-width: 620px;
line-height: 1.6;
}

.tag {
border: 2px solid #111;
background: #f2f2f2;
font-family: ui-monospace, SFMono-Regular, monospace;
}
 

This is a paragraph with an inline tag sitting inside the text. Notice how it flows like a word.

Learn more about display: inline in the CSS Display Inline Interactive Tutorial.

display: inline-block (the “inline but measurable” box)

Inline-block sits on the same line like inline text, but behaves like a box: it respects width, height, and vertical padding/margins more predictably.

Use inline-block when you want something to line up with text, but still have “box powers”. Common examples: badges, small buttons, icon+label chips.

 .badge { display: inline; width: 170px; height: 50px; } 
 .badge { display: inline-block; width: 170px; height: 50px; } 
 .badge { display: inline-block; width: 170px; height: 50px; vertical-align: middle; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}

.line {
border: 2px dashed #bbb;
padding: 12px;
line-height: 1.8;
}

.badge {
border: 3px solid #111;
background: #f2f2f2;
font-family: ui-monospace, SFMono-Regular, monospace;
padding: 6px 10px;
}
 
Before Badge After

Learn more about display: inline-block in the CSS Display Inline-Block Interactive Tutorial.

display: none (remove from layout)

display: none removes the element from the layout entirely:

  • It takes up no space
  • It is not visible
  • It’s not focusable (because it’s effectively not there)

This is different from visibility: hidden, which hides the element but keeps its space reserved.

 .ghost { display: none; } 
 .ghost { visibility: hidden; } 
 .ghost { opacity: 0; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}

.row {
display: flex;
gap: 12px;
align-items: center;
}

.box {
width: 140px;
height: 60px;
border: 3px solid #111;
background: #f2f2f2;
display: grid;
place-items: center;
font-family: ui-monospace, SFMono-Regular, monospace;
}

.hint {
margin-top: 10px;
max-width: 620px;
color: #333;
}
 
Left
Middle
Right

Snippet 1 removes the middle box completely. Snippet 2 hides it but keeps the gap. Snippet 3 makes it invisible but it still takes space.

Learn more about display: none in the CSS Display None Interactive Tutorial.

display: flex (one-dimensional layout)

Flexbox is a layout mode that arranges children in a single direction: row (left-to-right) or column (top-to-bottom).

You put display: flex on the parent container. Its direct children become “flex items”.

  • flex-direction chooses row or column
  • gap adds spacing between items
  • justify-content aligns items along the main axis
  • align-items aligns items along the cross axis
justify-content:
 .flex { display: flex; justify-content: start; } 
 *, ::before, ::after { box-sizing: border-box; } .wrap { padding: 18px; font-family: system-ui, Arial, sans-serif; } .flex { border: 3px solid #111; background: #f2f2f2; padding: 12px; gap: 10px; } .flex > div { border: 2px solid #111; background: #fff; padding: 10px 14px; font-family: ui-monospace, SFMono-Regular, monospace; } 
 
One
Two
Three
Four

Learn more about display: flex in the CSS Flexbox Interactive Tutorial.

display: inline-flex (flex that doesn’t break the line)

inline-flex creates a flex container, but the container itself behaves like an inline element. That means it can sit inside a line of text without forcing a new line.

The children are still laid out with flexbox. The difference is mainly “outer behavior”.

 .pill-row { display: flex; } 
 .pill-row { display: inline-flex; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}

.line {
border: 2px dashed #bbb;
padding: 12px;
line-height: 2;
}

.pill-row {
border: 3px solid #111;
background: #f2f2f2;
padding: 6px;
gap: 6px;
vertical-align: middle;
}

.pill {
border: 2px solid #111;
background: #fff;
padding: 6px 10px;
font-family: ui-monospace, SFMono-Regular, monospace;
}
 
Before A B C After

Learn more about display: inline-flex in the CSS Display Inline-Flex Interactive Tutorial.

display: grid (two-dimensional layout)

CSS Grid is built for two-dimensional layouts: rows and columns at the same time. Like flexbox, you set display: grid on a parent, and its direct children become grid items.

A beginner-friendly way to start is with columns:

  • grid-template-columns defines your columns
  • gap sets spacing between cells
  • place-items can align content inside each grid cell
 .grid { display: grid; grid-template-columns: repeat(3, 1fr); } 
 .grid { display: grid; grid-template-columns: 120px 1fr 2fr; } 
 .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}

.grid {
border: 3px solid #111;
background: #f2f2f2;
padding: 12px;
gap: 10px;
}

.cell {
border: 2px solid #111;
background: #fff;
padding: 12px;
font-family: ui-monospace, SFMono-Regular, monospace;
text-align: center;
}
 
1
2
3
4
5
6

Learn more about display: grid in the CSS Grid Interactive Tutorial.

display: contents (the “ghost wrapper”)

display: contents is a special one. It makes the element’s box disappear, but its children stay and behave as if they were direct children of the parent.

This can be useful when you have a wrapper element in your HTML for grouping, but you don’t want it to affect layout.

  • The wrapper’s own background/border won’t show (because its box is gone)
  • The wrapper no longer participates in layout as a box
  • The children “move up” one level for layout purposes

Beginner note: it’s powerful, but it can be confusing. Use it when you truly need it, not as a default.

Switch to the HTML tab to see what's going on more clearly.

 .wrapper { display: block; } 
 .wrapper { display: contents; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}

.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
border: 3px solid #111;
background: #f2f2f2;
padding: 12px;
}

.wrapper {
border: 3px dashed #666;
background: rgba(0, 0, 0, 0.06);
padding: 10px;
}

.item {
border: 2px solid #111;
background: #fff;
padding: 12px;
font-family: ui-monospace, SFMono-Regular, monospace;
text-align: center;
}
 
A
B
C
D

Learn more about display: contents in the CSS Display Contents Interactive Tutorial.

Common display values you’ll see in the wild

display: list-item (lists behave like lists)

List elements like li have list behavior (markers). You can apply display: list-item to other elements too, but most of the time you’ll just style lists using CSS list-style.

 .fake-li { display: list-item; } 
 .fake-li { display: block; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}

.list {
border: 2px dashed #bbb;
padding: 14px 14px 14px 34px;
max-width: 520px;
}

.fake-li {
margin: 6px 0;
font-family: ui-monospace, SFMono-Regular, monospace;
}
 
Looks like an li
But it is a div
CSS is mischievous

Learn more about styling list-item elements in the CSS UL Style Interactive Tutorial.

display: table (table-like layout without a table)

CSS has table display values (table, table-row, table-cell). They can be handy for very specific cases, but for modern layouts, flex and grid are preferable.

Still, it’s useful to recognize them when you bump into older code.

 .table { display: table; } .row { display: table-row; } .cell { display: table-cell; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}

.table {
border: 3px solid #111;
background: #f2f2f2;
padding: 8px;
}

.cell {
border: 2px solid #111;
background: #fff;
padding: 10px 12px;
font-family: ui-monospace, SFMono-Regular, monospace;
}
 
Name
Role
Level
Ada
Engineer
Senior

display: flow-root (the float-fix in a property)

flow-root creates a new “block formatting context”. In normal human terms: it helps a parent contain floated children without hacks.

If you’ve ever seen “clearfix” CSS, flow-root is the modern, tidy version for many cases.

 .container { display: block; } 
 .container { display: flow-root; } 
 *, ::before, ::after { box-sizing: border-box; }

.wrap {
padding: 18px;
font-family: system-ui, Arial, sans-serif;
}

.container {
border: 3px solid #111;
background: #f2f2f2;
padding: 12px;
}

.floaty {
float: left;
width: 160px;
height: 70px;
border: 2px solid #111;
background: #fff;
display: grid;
place-items: center;
font-family: ui-monospace, SFMono-Regular, monospace;
margin-right: 12px;
}

.text {
font-size: 14px;
line-height: 1.6;
max-width: 620px;
}
 
Float

This paragraph sits next to the float. The interesting part is the container’s border: with normal block display, the float can “escape” the container’s height. With flow-root, the container properly wraps around the floated box.

Choosing the right display value

Here’s a practical “when should I use what?” cheat sheet:

  • block — sections, cards, containers, anything that should start on a new line.
  • inline — styling a piece of text inside a sentence (links, emphasis, small tags).
  • inline-block — small UI bits that sit inline but need width/height (badges, small buttons).
  • none — hide/remove entirely (menus, toggles, responsive patterns).
  • flex — one-direction layout: nav bars, toolbars, rows of cards, vertical stacks with alignment.
  • inline-flex — flex layout, but the container sits inline (icon+label groups inside text).
  • grid — true row+column layouts: galleries, dashboards, page sections.
  • contents — remove a wrapper box while keeping children in the layout flow.

Common gotchas and debugging tips

  • “Why won’t my width apply?”

    Check if the element is display: inline. Inline elements usually ignore width and height. Try inline-block, block, or a layout container like flex.

  • “Why is there space under my inline-block?”

    Inline and inline-block align to the text baseline by default. Try vertical-align: middle (or top).

  • “My flex/grid item won’t shrink and overflows!”

    By default, some items keep their content’s minimum size. In flex layouts, adding min-width: 0 to a flex item is a common fix for overflowing text.

  • “display: none vs visibility: hidden vs opacity: 0”

    none removes it from layout, visibility: hidden keeps space, and opacity: 0 makes it invisible but still interactive unless you also disable pointer events.

  • “Flex or Grid?”

    If you’re laying things out in one direction, start with flex. If you’re thinking in rows and columns, start with grid.

display:
 .demo-switch { display: block; } 
 *, ::before, ::after { box-sizing: border-box; } .wrap { padding: 18px; font-family: system-ui, Arial, sans-serif; } .line { border: 2px dashed #bbb; padding: 12px; line-height: 2; } .demo-switch { border: 3px solid #111; background: #f2f2f2; padding: 10px; gap: 8px; } .demo-switch > span { border: 2px solid #111; background: #fff; padding: 8px 10px; font-family: ui-monospace, SFMono-Regular, monospace; text-align: center; } .demo-switch > span:nth-child(1) { } .demo-switch > span:nth-child(2) { } .demo-switch > span:nth-child(3) { } 
 
Before
One Two Three
After

Wrap-up: what you should remember

  1. display decides layout behavior. It affects both how an element fits into its parent and how it lays out its children.

  2. inline flows with text and doesn’t treat width/height like a normal box.

  3. inline-block is the “inline box”. Great when you need dimensions but still want inline flow.

  4. none removes the element completely from the layout.

  5. flex is for one dimension (row or column), and grid is for two (rows and columns).

  6. contents removes the wrapper’s box but keeps its children in the layout.