Every HTML element has a default display type that determines how it participates in the page flow — whether it starts a new line, sits inline with text, or is removed from the flow entirely. The display property is the single most important layout property in CSS, and understanding its values is the prerequisite for mastering Flexbox, Grid, and positioning. In this lesson you will learn every major display value and exactly when to use each one.
Core Display Values
| Value | Flow Behaviour | Width Behaviour | Default Elements |
|---|---|---|---|
block |
Starts on a new line; takes full available width | Respects width/height | div, p, h1-h6, section |
inline |
Flows with text; no line break before/after | Ignores width/height; sized by content | span, a, strong, em |
inline-block |
Flows with text like inline | Respects width, height, padding, margin | None by default — set explicitly |
none |
Removed from layout and accessibility tree | Takes no space at all | Used to toggle visibility |
flex |
Block-level; creates flex formatting context for children | Respects width/height | None by default — set explicitly |
grid |
Block-level; creates grid formatting context for children | Respects width/height | None by default — set explicitly |
inline-flex |
Inline-level flex container — sits in text flow | Sized by content (like inline) | None by default — badges, tags |
display: none vs visibility: hidden
| Property | Space in Layout | Accessible to Screen Readers | Use Case |
|---|---|---|---|
display: none |
No — element is completely removed | No — hidden from accessibility tree | Toggle elements on/off (menus, modals) |
visibility: hidden |
Yes — space is preserved | No — hidden from accessibility tree | Animate out while keeping layout stable |
opacity: 0 |
Yes — space is preserved | Yes — still accessible and interactive | Fade animations; still receives pointer events |
block vs inline-block Key Differences
| Feature | block | inline-block |
|---|---|---|
| New line | Yes — always starts on its own line | No — flows inline with surrounding content |
| width / height | Fully respected | Fully respected |
| vertical margin | Fully respected | Fully respected |
| Use case | Sections, containers, paragraphs | Buttons, badges, nav items in text |
display: none removes the element from both visual layout and the accessibility tree. If you need content to be hidden visually but remain accessible to screen readers (e.g. a skip-navigation link), use the visually-hidden CSS technique instead: position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0);display: inline-flex for small component containers like badges, tags, and chip elements that need to flow inline with text but require internal flex alignment of an icon + label. It behaves like an inline element from the outside and like a flex container on the inside.display: block on an anchor tag (<a>) changes its inline behaviour — the entire block becomes clickable but it will start on a new line. Use display: inline-block if you want it to remain inline but respect padding and size. Use display: block inside navigation lists where the full row should be clickable.Basic Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSS Display Values</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; padding: 32px; background: #f8fafc; line-height: 1.6; }
/* block — new line, full width */
.demo-block {
display: block;
background: #ede9fe;
border-left: 4px solid #7c3aed;
padding: 12px 16px;
margin-bottom: 12px;
border-radius: 0 8px 8px 0;
}
/* inline — flows in text, ignores width/height */
.demo-inline {
display: inline;
background: #fef9c3;
padding: 2px 6px;
border-radius: 4px;
font-weight: 600;
}
/* inline-block — flows in text but respects sizing */
.demo-inline-block {
display: inline-block;
background: #d1fae5;
border: 1px solid #6ee7b7;
padding: 8px 16px;
border-radius: 6px;
font-weight: 600;
margin: 4px;
/* width and height are respected here unlike plain inline */
min-width: 100px;
text-align: center;
}
/* Toggling display: none */
.hidden-demo { display: none; } /* takes NO space */
.invisible-demo { visibility: hidden; } /* space preserved */
/* inline-flex badge example */
.badge {
display: inline-flex;
align-items: center;
gap: 4px;
background: #4f46e5;
color: white;
padding: 3px 10px;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 700;
}
/* Block link — full-width clickable row */
.nav-link {
display: block;
padding: 12px 20px;
background: white;
border: 1px solid #e2e8f0;
border-radius: 8px;
text-decoration: none;
color: #1e293b;
margin-bottom: 8px;
font-weight: 500;
transition: background 0.15s, border-color 0.15s;
}
.nav-link:hover { background: #ede9fe; border-color: #c4b5fd; }
</style>
</head>
<body>
<div class="demo-block">display: block — starts on its own line, full width</div>
<div class="demo-block">Second block — also on its own line</div>
<p>
Normal paragraph text with
<span class="demo-inline">inline span</span>
that flows naturally — and another
<span class="demo-inline">inline badge</span>
right here in the text.
</p>
<p>
Inline-block elements sit in text flow but respect sizing:
<span class="demo-inline-block">Button A</span>
<span class="demo-inline-block">Button B</span>
<span class="demo-inline-block">Btn C</span>
— back to regular text.
</p>
<p>display: none removes the box: [<span class="hidden-demo">HIDDEN</span>] — no gap there.</p>
<p>visibility: hidden preserves space: [<span class="invisible-demo">INVISIBLE</span>] — gap remains.</p>
<p>
inline-flex badge in text:
<span class="badge">✓ Verified</span>
— flows with surrounding content.
</p>
<a href="#" class="nav-link">Block-level link — entire row is clickable</a>
<a href="#" class="nav-link">Second block-level link</a>
</body>
</html>
How It Works
Step 1 — Block Elements Stack Vertically
Each .demo-block div creates its own line in the flow. Even with text content shorter than the viewport, a block element extends to the full container width. Siblings stack below it regardless of available horizontal space.
Step 2 — Inline Elements Run in Text Flow
The two .demo-inline spans sit between words without breaking the line. They cannot have a meaningful width, height, or vertical margin — those properties are simply ignored for inline elements.
Step 3 — Inline-Block Bridges Both Worlds
The three .demo-inline-block spans sit side by side on the same line (inline behaviour) but each has a min-width that is honoured (block behaviour). This makes them ideal for button groups that must live within a paragraph or heading.
Step 4 — display: none Collapses the Box Entirely
The hidden span produces no rendered box whatsoever — the bracketed text around it appears with no gap. In contrast, the visibility:hidden span leaves a blank space exactly equal to its rendered size.
Step 5 — inline-flex Enables Internal Alignment Within Text Flow
The badge is inline-flex so it aligns the checkmark and text vertically via align-items: center — not possible with plain inline. From the outside it flows naturally in the sentence, from the inside it is a flex container.
Real-World Example: Navigation Link List
/* sidebar-nav.css */
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; margin: 0; }
.sidebar {
width: 260px;
background: #1e293b;
min-height: 100vh;
padding: 24px 0;
}
.nav-section-label {
display: block; /* block so it fills full width */
padding: 6px 20px;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: #64748b;
margin-bottom: 4px;
}
.nav-item {
display: flex; /* flex container for icon + text */
align-items: center;
gap: 10px;
padding: 10px 20px;
color: #94a3b8;
text-decoration: none;
font-size: 0.875rem;
border-radius: 0;
transition: background 0.15s, color 0.15s;
}
.nav-item:hover { background: #334155; color: #f1f5f9; }
.nav-item.active { background: #312e81; color: #a5b4fc; font-weight: 600; }
.nav-icon {
display: inline-flex; /* inline-flex for icon centering */
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
flex-shrink: 0;
font-size: 1rem;
}
.nav-badge {
display: inline-flex;
align-items: center;
margin-left: auto;
background: #4f46e5;
color: white;
font-size: 0.65rem;
font-weight: 700;
padding: 2px 7px;
border-radius: 9999px;
min-width: 20px;
justify-content: center;
}
/* Divider */
.nav-divider {
display: block;
height: 1px;
background: #334155;
margin: 12px 20px;
}
Common Mistakes
Mistake 1 — Setting width/height on inline elements
❌ Wrong — width and height are ignored on inline elements:
span { display: inline; width: 200px; height: 40px; } /* has no effect */
✅ Correct — switch to inline-block or block to apply sizing:
span { display: inline-block; width: 200px; height: 40px; }
Mistake 2 — Using display: none for accessible content
❌ Wrong — screen readers cannot reach this content:
.skip-link { display: none; } /* inaccessible to keyboard/screen reader */
✅ Correct — use the visually-hidden technique to hide only visually:
.visually-hidden {
position: absolute;
width: 1px; height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
Mistake 3 — Unexpected gaps between inline-block elements
❌ Wrong — whitespace in HTML creates a small gap between inline-block items:
<span class="btn">A</span>
<span class="btn">B</span> <!-- gap appears between A and B -->
✅ Correct — use flexbox on the parent to eliminate whitespace gaps entirely:
.btn-group { display: flex; gap: 8px; }
.btn-group .btn { /* no display: inline-block needed */ }
Quick Reference
| Value | New Line? | Width/Height? | Common Use |
|---|---|---|---|
block |
Yes | Yes | Containers, headings, paragraphs |
inline |
No | No | Text styling: span, a, strong |
inline-block |
No | Yes | Buttons within text, nav pills |
none |
— | — | Toggle elements; removes from layout |
flex |
Yes (outer) | Yes | Row/column layout of children |
inline-flex |
No | Content-sized | Badges, chips, icon+label in text |
grid |
Yes (outer) | Yes | Two-dimensional child layout |