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/heightapply - 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 AfterTry 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, andpaddingnormally
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.
widthandheightwon’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;
}
LeftMiddleRightSnippet 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-directionchooses row or columngapadds spacing between itemsjustify-contentaligns items along the main axisalign-itemsaligns items along the cross axis
.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; }
OneTwoThreeFour
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-columnsdefines your columnsgapsets spacing between cellsplace-itemscan 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;
}
123456
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;
}
ABCD
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 liBut it is a divCSS 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;
}
NameRoleLevelAdaEngineerSenior
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;
}
FloatThis 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 ignorewidthandheight. Tryinline-block,block, or a layout container likeflex. - “Why is there space under my inline-block?”
Inline and inline-block align to the text baseline by default. Try
vertical-align: middle(ortop). - “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: 0to a flex item is a common fix for overflowing text. - “display: none vs visibility: hidden vs opacity: 0”
noneremoves it from layout,visibility: hiddenkeeps space, andopacity: 0makes 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.
.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) { }
BeforeOne Two ThreeAfter
Wrap-up: what you should remember
-
displaydecides layout behavior. It affects both how an element fits into its parent and how it lays out its children. -
inlineflows with text and doesn’t treat width/height like a normal box. -
inline-blockis the “inline box”. Great when you need dimensions but still want inline flow. -
noneremoves the element completely from the layout. -
flexis for one dimension (row or column), andgridis for two (rows and columns). -
contentsremoves the wrapper’s box but keeps its children in the layout.
