HTMLBlock vs Inline Elements

Block vs Inline Elements

Every HTML element has a default rendering behavior described by its CSS display value: most are either block-level or inline-level. Understanding the difference explains a lot of "why doesn't my layout look right" moments, and it explains why certain elements can't be nested inside others.

Block-Level Elements

Block-level elements start on a new line and stretch to fill the width of their parent container by default. They can contain other block-level elements as well as inline elements, and they respect top/bottom margin.

Element

Typical use

<div>

Generic block container, no inherent meaning

<p>

A paragraph of text

<h1><h6>

Section headings

<ul>, <ol>, <li>

Lists and list items

<section>, <article>, <header>, <footer>

Semantic page regions

<table>, <form>

Tabular data, form containers

block-example.html

HTML
<div>
  <h2>Article Title</h2>
  <p>Each of these starts on its own line and fills the available width.</p>
</div>
Inline-Level Elements

Inline-level elements flow within a line of text, only taking up as much width as their content needs. They don't force a line break before or after themselves, and top/bottom margin has no effect on layout (though left/right margin and padding do apply).

Element

Typical use

<span>

Generic inline container, no inherent meaning

<a>

Hyperlinks

<strong>, <em>

Emphasis within a sentence

<img>

An image embedded in a line of text or on its own

<code>, <abbr>, <time>

Inline semantic text markers

<label>, <button> (mostly)

Small interactive controls that flow with text

inline-example.html

HTML
<p>
  Read the <a href="/docs">docs</a>, then check the
  <strong>quick start</strong> guide. Each of these stays
  <em>within</em> the flow of this single line of text.
</p>
Side by Side

Behavior

Block-level

Inline-level

Starts on a new line

Yes

No — flows with surrounding text

Width

Fills parent by default

Only as wide as its content

Height

Respects height/width you set

Height mostly follows content

Top/bottom margin

Applied

Ignored for layout purposes

Can contain block children

Usually yes

No — only other inline content

Why You Can't Nest Block Inside Inline

Semantically, an inline element represents a run of text within a larger flow — it doesn't make sense for a "run of text" to contain a whole section, a list, or a table. The HTML content model reflects this: inline elements are only allowed to contain "phrasing content" (other inline-level things), not block-level elements.

Putting a block element inside a link or span
Historically, <a> could only wrap phrasing content, so something like <a><div>...</div></a> was invalid. HTML5 relaxed this specifically for <a>, which may now wrap block-level content when the whole block should be clickable. Most other inline elements (<span>, <strong>, <em>) still may not.

anchor-wrapping-block.html

HTML
<!-- Valid in HTML5: <a> may wrap block-level content -->
<a href="/product/42" class="card-link">
  <h3>Wireless Keyboard</h3>
  <p>Compact, backlit, and rechargeable.</p>
</a>

<!-- Invalid: <span> may not contain block-level content -->
<span>
  <div>This breaks the content model</div>
</span>
CSS Can Override the Default display

"Block" and "inline" describe the default rendering behavior baked into the browser's built-in stylesheet — they are not fixed, unchangeable categories. Any element's display property can be overridden with CSS.

override-display.css

CSS
/* Make an inline <span> behave like a block box */
span.callout {
  display: block;
}

/* Make a block-level <li> flow inline, e.g. for a horizontal nav */
nav li {
  display: inline-block;
}
Display doesn't change the content model
Setting display: block on a <span> changes how it's rendered, but it doesn't change what HTML considers valid to nest inside it — the parser still enforces the original content model based on the element type, not its computed CSS display value.
display: inline-block is a common middle ground
inline-block flows with surrounding text like an inline element but respects width, height, and vertical margin like a block element — useful for things like custom buttons or nav items that need to sit in a row but also need box-model control.
  • Block-level elements stack vertically and fill their parent's width by default.

  • Inline-level elements flow horizontally within a line of text.

  • The HTML content model restricts what can nest inside what, independent of CSS.

  • CSS display can change how something renders without changing what's valid to nest inside it.

Modern display Values Beyond Block and Inline

The block/inline distinction predates CSS3's richer layout models. flex and grid create entirely new layout contexts for their children, while inline-flex and inline-grid do the same but flow the container itself inline, like an inline-level box.

display value

Container behaves like

Children laid out by

flex

Block-level box

Flexbox algorithm

inline-flex

Inline-level box

Flexbox algorithm

grid

Block-level box

Grid algorithm

inline-grid

Inline-level box

Grid algorithm

flex-container.css

CSS
.toolbar {
  display: flex; /* the toolbar itself is a block-level box */
  gap: 8px;
}
Semantic Elements Are Still Block by Default

HTML5's newer sectioning elements — <section>, <article>, <header>, <footer>, <nav>, <aside>, <main> — are all block-level by default in the browser's built-in stylesheet, even though "semantic" and "block" describe unrelated properties. Don't assume an element is inline just because it's new or unfamiliar; check its default display value.

Category

Examples

Default display

Sectioning

section, article, nav, aside

block

Grouping

header, footer, main, div, figure

block

Text-level semantics

span, a, strong, em, time, abbr

inline

Table-related

table, tr, td

table, table-row, table-cell

A Practical Debugging Tip

When a layout doesn't behave as expected — an element refuses to accept a width, or two elements won't sit side by side — checking its computed display value in browser dev tools is often the fastest way to understand why.

debug-with-devtools.css

CSS
/* In DevTools > Computed tab, look for: */
display: inline; /* width/height on this element will be ignored */
Table-related display values are their own category
<table>, <tr>, and <td> use table-specific display values (table, table-row, table-cell) that don't fit neatly into "block" or "inline" — they follow their own layout rules unless overridden with CSS.