The Two Fundamental Types: Block vs Inline
Before modern layout modes (flexbox, grid), every HTML element was either block or inline. Understanding this distinction is still fundamental:
display: block
Block elements:
- Start on a new line
- Stretch to fill the full width of their container
- Respect
width,height,margin,paddingon all sides - Stack vertically, one below the other
Default block elements: <div>, <p>, <h1>–<h6>, <section>, <article>, <header>, <footer>, <ul>, <li>, <form>
.box { display: block; background: #e8f4fd; padding: 12px; margin-bottom: 8px; }
display: inline
Inline elements:
- Flow within text — like words in a sentence
- Only take up as much width as their content
- Do not start a new line
widthandheightare ignored- Vertical
marginandpaddingare partially ignored (don't push other elements)
Default inline elements: <span>, <a>, <strong>, <em>, <img>, <button>, <input>, <label>, <code>
display: inline-block
The best of both worlds:
- Flows inline (doesn't force a new line)
- Respects
width,height, verticalmargin, andpaddinglike a block
Use cases: navigation links, badges, buttons that should sit inline but need sizing control.
.nav-link {
display: inline-block;
padding: 8px 16px;
margin-right: 4px;
background: #1572B6;
color: white;
border-radius: 4px;
text-decoration: none;
}
display: none – Hiding Elements
display: none removes the element from the page entirely — it takes up no space, is not visible, and is not announced by screen readers.
/* Remove from layout entirely */
.hidden { display: none; }
/* Common pattern: toggle with JavaScript */
.modal { display: none; }
.modal.is-open { display: flex; }
/* Responsive hiding */
@media (max-width: 768px) {
.desktop-only { display: none; }
}
display: none — element removed from layout, takes no space, not readable by screen readers.
visibility: hidden — element invisible but still occupies space. Not readable by screen readers.
opacity: 0 — element invisible but still occupies space AND is readable by screen readers. Can receive pointer events unless pointer-events: none is also set.
display: flex
Turns the element into a flex container. Its direct children become flex items that can be arranged horizontally or vertically, aligned, and distributed with powerful properties.
.nav {
display: flex;
gap: 16px;
align-items: center;
justify-content: space-between;
}
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
Flexbox is covered in depth in the next lesson. It is the most-used layout tool in modern CSS.
display: grid
Turns the element into a grid container. Creates a two-dimensional layout system with rows and columns.
.layout {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
CSS Grid is covered in detail later in this course.
Other display Values
/* flow-root — creates a new block formatting context
Useful to contain floats and prevent margin collapse */
.clearfix { display: flow-root; }
/* contents — element's box is removed but children render normally
Useful for semantic wrapper elements that shouldn't affect layout */
.wrapper { display: contents; }
/* table values — make non-table elements behave like table cells */
.row { display: table-row; }
.cell { display: table-cell; vertical-align: middle; }
/* Rarely needed — flexbox/grid are almost always better */
/* list-item — element generates a block box with a list marker */
.custom-list-item { display: list-item; list-style: disc; }
/* inline-flex — flex container that flows inline */
.tag { display: inline-flex; align-items: center; gap: 4px; }
/* inline-grid — grid container that flows inline */
.mini-grid { display: inline-grid; grid-template-columns: 1fr 1fr; }
Default Display Values by Element
BLOCK by default:
div, p, h1-h6, section, article, header, footer, main, nav,
aside, ul, ol, li, dl, dt, dd, form, fieldset, blockquote, pre,
table, hr, figure, figcaption
INLINE by default:
span, a, strong, em, b, i, u, s, small, code, kbd, mark,
abbr, cite, q, sub, sup, label, button, input, select, textarea,
img, svg, video, canvas
NONE by default:
script, style, head, meta, link, title
Setting display: block on a <span> makes it visually behave like a block, but it is still a <span> semantically — screen readers still treat it as an inline element. Similarly, setting display: inline on a heading doesn't change its heading level for accessibility. Use the right HTML element for the right semantic purpose, then adjust display for visual layout.
📋 Summary
- block — full width, new line, respects all box model properties. Default for divs, headings, paragraphs.
- inline — flows in text, no width/height, vertical margin ignored. Default for spans, links.
- inline-block — inline flow + full box model support. Great for buttons and nav items.
- none — removes element from layout entirely. Takes no space. Not accessible.
- flex — one-dimensional layout. Best for rows/columns of items.
- grid — two-dimensional layout. Best for complex page layouts.
- flow-root — contains floats, prevents margin collapse.
- contents — element box removed, children rendered normally.
Frequently Asked Questions
display: none removes the element completely — it takes no space, other elements reflow to fill its position, and screen readers do not announce it. visibility: hidden makes the element invisible but it still occupies its space in the layout (a blank gap remains). Neither triggers layout reflow when toggled with JavaScript — display: none does trigger reflow, while visibility: hidden only triggers repaint. For accessible hiding (visually hidden but readable by screen readers), use the .sr-only class pattern instead of either property.
inline-block is useful for simple cases: a row of navigation links, a series of badges or tags, or a button that sits inline within paragraph text. It's simpler to set up than flex when you just need elements side by side. Use flexbox when you need alignment control (vertical centering, space-between), wrapping behavior, or any kind of responsive distribution. In modern CSS, flexbox handles most cases where inline-block was previously used.
Two requirements for margin: 0 auto centering: (1) The element must have display: block (or block-level). Inline elements can't be centered this way. (2) The element must have an explicit width smaller than its container — without a width, a block stretches to 100% and has no space to distribute. Fix: set display: block and add max-width: 800px; width: 100%; margin: 0 auto.
display: contents makes the element's own box disappear from the layout, but its children render as if they were direct children of the element's parent. This is useful when you have a semantic wrapper element (like a <ul>) that you want to participate in a flex or grid layout without the wrapper creating an extra layout layer. Be aware: it removes the element from the accessibility tree in some browsers — use with caution.