The Display Property
📐 Chapter 6 — The display Property
Every HTML element has a default layout behaviour — some elements stack vertically and stretch to fill the available width; others flow alongside text and shrink to fit their content. The display property is the switch that controls this behaviour, and changing it is one of the most powerful single-property changes you can make in CSS. Understanding block, inline, and inline-block is the foundation of everything that comes after — including Flexbox and Grid.
1 — How display Works
The display property does two things simultaneously: it controls how the element itself is laid out in the page flow (its outer display type), and how its children are arranged inside it (its inner display type). For now, we are focusing on the outer type — block, inline, and inline-block. Flexbox and Grid, which control the inner arrangement of children, are covered in the Intermediate course.
.element { display: block; } /* stacks vertically, full width */
.element { display: inline; } /* flows with text, no width/height */
.element { display: inline-block; } /* flows with text, accepts width/height */
.element { display: none; } /* removed from layout entirely */
.element { display: flex; } /* block-level flex container (Intermediate) */
.element { display: grid; } /* block-level grid container (Intermediate) */
2 — display: block
A block element:
- Starts on a new line — always breaks away from what came before it.
- Stretches to fill the full width of its containing element by default.
- Stacks vertically — each block element sits below the last.
- Respects all box model properties — width, height, margin, and padding all work as expected.
.block-box {
display: block;
width: 300px; /* width works — limits stretching */
height: 80px; /* height works */
padding: 16px; /* padding works on all four sides */
margin: 20px 0; /* margin works on all four sides */
background-color: #1a2e1a;
}
/* Without a width set, a block fills its container */
.full-width {
display: block;
/* no width — stretches to 100% of parent */
}
Common block elements
These HTML elements are block by default — you do not need to set display: block on them:
<div> <p> <h1>–<h6> <ul> <ol> <li> <section> <article> <header> <footer> <nav> <main> <aside> <form> <blockquote> <pre> <hr> <table>
3 — display: inline
An inline element:
- Flows with the surrounding text — it does not break onto a new line.
- Shrinks to fit its content — it takes up only as much space as its content needs.
- Ignores width and height — you cannot set these properties on an inline element.
- Respects horizontal padding and margin only — vertical padding and margin are applied visually but do not push surrounding block elements away.
span {
display: inline; /* default for span — shown here for clarity */
color: #ffd580; /* colour works */
background: #2a1e0a; /* background works */
padding: 2px 6px; /* horizontal padding works as expected */
/* vertical padding shows but doesn't push block siblings */
width: 200px; /* IGNORED — width has no effect on inline */
height: 50px; /* IGNORED — height has no effect on inline */
margin-top: 20px; /* IGNORED — vertical margin doesn't affect flow */
}
inline-block.Common inline elements
<span> <a> <strong> <em> <code> <img> <button> <input> <label> <abbr> <cite> <sup> <sub>
width and height. They are called replaced elements — the browser replaces them with external content (an image, a widget) — and they follow slightly different rules.
4 — display: inline-block
inline-block gives you the best of both worlds:
- Flows with surrounding content like an inline element — sits next to other elements on the same line.
- Respects width, height, padding, and margin on all sides — just like a block element.
This makes inline-block the go-to for elements that should sit side by side but still need a defined size — buttons, navigation items, image thumbnails, badges.
width: 120px
width: 120px
width: 120px
/* Navigation links side by side with padding */
nav a {
display: inline-block;
padding: 10px 20px;
background: #1a1d27;
border-radius: 4px;
text-decoration: none;
}
/* Fixed-size image thumbnails in a row */
.thumbnail {
display: inline-block;
width: 100px;
height: 100px;
object-fit: cover;
border-radius:4px;
margin-right: 8px;
}
/* Badges / tags */
.badge {
display: inline-block;
padding: 3px 10px;
border-radius: 999px;
font-size: 0.8rem;
font-weight: 600;
vertical-align:middle;
}
The whitespace gap problem
When you write inline-block elements on separate lines in your HTML, the browser treats the newline character between them as a space — creating a small gap between the elements that you did not add with margin. This is a well-known quirk.
<!-- These three items will have a small gap between them -->
<div class="item">One</div>
<div class="item">Two</div>
<div class="item">Three</div>
<!-- Workaround 1: put closing/opening tags on the same line -->
<div class="item">One</div><div class="item">Two</div><div class="item">Three</div>
.parent {
font-size: 0; /* collapses the whitespace text node */
}
.parent .item {
display: inline-block;
font-size: 1rem; /* restore font size on the children */
}
5 — Side-by-Side Comparison
6 — display: none
display: none removes an element from the page entirely — it takes up no space and is completely invisible. The element still exists in the HTML; it is just not rendered. This is commonly used to show and hide elements with JavaScript.
/* display: none — element removed from layout, no space taken */
.hidden {
display: none;
}
/* visibility: hidden — element invisible but STILL takes up space */
.invisible {
visibility: hidden;
}
/* opacity: 0 — also invisible but still takes space AND is interactive */
.transparent {
opacity: 0;
}
/* Toggling with a class (JavaScript adds/removes .is-open) */
.dropdown { display: none; }
.dropdown.is-open { display: block; }
display: none. If you need to hide something visually but keep it available to assistive technology (e.g. a label for an icon-only button), use the visually-hidden pattern instead — a CSS class that positions the element off-screen without removing it from the accessibility tree.
7 — Changing Default Display Values
One of the most common uses of display is overriding the default. You regularly need to make an inline element behave like a block, or make a block element flow inline.
/* Make links fill their container (e.g. nav links as blocks) */
nav a {
display: block;
padding: 12px 20px; /* now the whole row is clickable */
}
/* Make list items sit side by side (horizontal nav) */
ul.nav li {
display: inline-block;
}
/* Make an image a block to remove the inline baseline gap */
img {
display: block; /* eliminates the small gap below inline images */
}
/* Make a div sit inline with text */
.tag {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
background: #1e2235;
font-size: 0.8em;
}
8 — Default display Values
| Element(s) | Default display | Notes |
|---|---|---|
div, p, h1–h6, section, article, header, footer, nav, ul, ol, li |
block | Stack vertically, fill width |
span, a, strong, em, code, abbr, cite, sup, sub |
inline | Flow with text, no width/height |
img, button, input, select, textarea, label |
inline-block (or inline) | Flow with text but accept width/height — behaviour varies slightly by browser |
table |
table | Block-level, but uses table layout internally |
td, th |
table-cell | Inside a table only |
9 — Looking Ahead: flex and grid
Two more display values — flex and grid — are the foundation of modern CSS layout and are covered in full in Chapters 1–4 of the Intermediate course. Both create a block-level container whose children are laid out according to powerful new rules:
.nav {
display: flex;
gap: 16px;
align-items: center;
justify-content: space-between;
}
.page {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
gap: 24px;
}
display: flex on the parent would serve you better — it handles alignment and spacing far more cleanly, with no whitespace gap problem. But inline-block still has its place when you genuinely need elements to flow within text.
10 — Quick Reference
| Value | New line? | Full width? | Width/Height? | Best for |
|---|---|---|---|---|
block |
Yes | Yes (default) | Yes | Structural containers, paragraphs, headings |
inline |
No | No — shrinks to content | No | Text emphasis, links within paragraphs |
inline-block |
No | No — shrinks to content | Yes | Buttons, badges, nav items, image rows |
none |
— | — | — | Hiding elements completely (JS toggling) |
flex |
Yes (container) | Yes (container) | Yes | Rows, columns, alignment — see Intermediate Ch.1–2 |
grid |
Yes (container) | Yes (container) | Yes | Two-axis layouts — see Intermediate Ch.3–4 |
✏️ Exercises
Each exercise asks you to observe or change display behaviour. Open your browser's DevTools alongside each one — inspect the computed display value of elements and watch how the layout changes as you modify it.
<span> elements (normally inline) and three <div> elements (normally block). First observe them in their default state, then swap their display values: make the spans behave like blocks and the divs behave like inline elements. Give each a different background colour and some padding so the change is clearly visible.display: block to the span elements and display: inline to the div elements. Use a class to target each group separately.<span class="as-block">Span A</span>
<span class="as-block">Span B</span>
<span class="as-block">Span C</span>
<hr>
<div class="as-inline">Div X</div>
<div class="as-inline">Div Y</div>
<div class="as-inline">Div Z</div>
/* Spans made block */
.as-block {
display: block;
padding: 10px 16px;
margin: 6px 0;
background: #1a2e1a;
border: 1px solid #7ecfa0;
color: #7ecfa0;
font-family:system-ui, sans-serif;
}
/* Divs made inline */
.as-inline {
display: inline;
padding: 2px 8px;
background: #1a1a2e;
border: 1px solid #4f8ef7;
color: #4f8ef7;
font-family:system-ui, sans-serif;
}
<ul> and <li> elements — no extra wrapper divs. By default, <li> is a block element and the list stacks vertically. Change the <li> elements to inline-block to make them horizontal. Remove the list bullets, give each item padding, and style the links inside them. The whole item area (not just the link text) should be clickable.list-style: none on the <ul> to remove bullets. Make the <a> inside each <li> display: block so its padding fills the entire cell — this makes the full padded area clickable.<ul class="horiz-nav">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Projects</a></li>
<li><a href="#">Contact</a></li>
</ul>
.horiz-nav {
list-style: none;
padding: 0;
margin: 0;
background: #12141e;
font-size: 0; /* collapse whitespace gap */
}
.horiz-nav li {
display: inline-block;
font-size: 1rem; /* restore after the font-size:0 hack */
}
.horiz-nav a {
display: block;
padding: 14px 20px;
color: #a0a4b8;
text-decoration: none;
font-family: system-ui, sans-serif;
font-size: 0.88rem;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.horiz-nav a:hover {
color: #ffffff;
background: #1e2235;
}
<span class="tag"> elements inside it. Style the tags as inline-block with a rounded background, small padding, and a font smaller than the surrounding text. The tags should sit naturally within the text flow, not break onto their own line. Then, below the paragraph, create a standalone row of the same tags — notice they still flow left-to-right like inline elements.display: inline-block with padding: 2px 10px; border-radius: 999px; creates a pill-shaped tag. Use vertical-align: middle to align them nicely with the surrounding text baseline..tag {
display: inline-block;
padding: 2px 10px;
border-radius: 999px;
background: #1e2235;
border: 1px solid #2a2d3a;
color: #7ab8ff;
font-family: system-ui, sans-serif;
font-size: 0.78em;
font-weight: 600;
vertical-align: middle;
margin: 0 2px;
}
<div class="panel"> with some content inside it, and a <button> above it. Using a small amount of JavaScript, toggle a class of is-hidden on the panel when the button is clicked. In your CSS, set .is-hidden { display: none; }. The button text should change between "Show panel" and "Hide panel" depending on the state.element.classList.toggle('is-hidden') in a click event listener. For the button text, check panel.classList.contains('is-hidden') after toggling and update btn.textContent.<button id="toggle-btn">Hide panel</button>
<div class="panel" id="my-panel">
<h3>This is the panel</h3>
<p>Click the button to hide or show this content.</p>
</div>
.panel {
background: #1a1d27;
border: 1px solid #2a2d3a;
border-radius:6px;
padding: 20px;
margin-top: 12px;
color: #e2e4ec;
font-family: Georgia, serif;
}
.is-hidden {
display: none;
}
const btn = document.getElementById('toggle-btn');
const panel = document.getElementById('my-panel');
btn.addEventListener('click', () => {
panel.classList.toggle('is-hidden');
btn.textContent = panel.classList.contains('is-hidden')
? 'Show panel'
: 'Hide panel';
});
This pattern — toggling a class that sets display: none — is one of the most common JavaScript/CSS patterns in web development. Dropdowns, modals, accordions, and tabs all use variations of it.