div and span: When Nothing Else Fits

Two elements with no meaning at all, and that is the point. Learn what they are for, why they are not a failure, and how to know you have too many.

Concept

div and span are the only elements in HTML that mean nothing. They are generic containers: div is block level, span is inline, and neither says anything about its contents.

That is a feature. Sometimes you need to group elements purely so that CSS can lay them out, or wrap a few words purely so a script can find them. Using a meaningful element for that would be a lie.

divspan
DisplayBlockInline
MeaningNoneNone
May containBlock and inlineInline only
Typical useLayout wrapper, grid or flex containerStyling or scripting part of a sentence

Legitimate uses of div

<!-- a layout container with no meaning of its own -->
<div class="grid">
  <article>...</article>
  <article>...</article>
</div>

<!-- a scroll wrapper -->
<div class="table-scroll" tabindex="0" role="region" aria-label="Fee structure">
  <table>...</table>
</div>

<!-- pairing a term with its description inside a dl -->
<dl>
  <div class="spec-row">
    <dt>Capacity</dt>
    <dd>2 litres</dd>
  </div>
</dl>

<!-- a script hook -->
<div id="chart" data-endpoint="/api/ridership"></div>

Legitimate uses of span

<!-- styling part of a sentence with no semantic emphasis -->
<p>Total: <span class="amount">4,999</span></p>

<!-- a script target -->
<p>Seats remaining: <span id="seats">12</span></p>

<!-- a decorative icon inside a real button -->
<button type="button">
  <span class="icon" aria-hidden="true"></span>
  Add to cart
</button>

<!-- marking a language change mid sentence -->
<p>The dish is served with <span lang="hi">kadhi</span> on the side.</p>

When you should not have reached for them

You wroteYou wanted
<div class="button" onclick><button>
<div class="heading"><h2>
<div class="list-item"><li> inside a ul
<div class="nav"><nav>
<div class="footer"><footer>
<span class="bold"><strong>
<span class="italic"><em>
<div class="link" onclick><a href>

The pattern is unmistakable: if the class name describes something HTML already has an element for, use the element.

Div soup

The term for markup that is nothing but nested divs. It is worth recognising:

<div class="wrapper">
  <div class="container">
    <div class="row">
      <div class="col">
        <div class="card">
          <div class="card-inner">
            <div class="card-body">
              <div class="card-title">Design</div>
              <div class="card-text">Three years</div>
<!-- ... -->

Every wrapper here exists for a stylesheet, and the actual content - a title and a description - has been stripped of meaning on the way. Modern CSS grid and flexbox remove most of the need for these layers, and the two content divs should be a heading and a paragraph.

How many is too many

There is no fixed number, but three signals are reliable:

  • A div whose class name matches an existing element name.
  • More than three or four wrapper levels with no content between them.
  • A page with no main, no nav, no headings and no lists.

The stylesheet off test settles it. If the page collapses into an undifferentiated block of text, the meaning was in the CSS.

What about the wrapper divs a framework generates?

Component frameworks emit wrappers, and that is largely fine - they are structural, not semantic claims. What matters is the elements you choose inside them. A card component whose root is a generated div but whose contents are an article, an h3, a p and an a is good markup.

Important rules

  • Neither element has any meaning, and neither is exposed to assistive technology.
  • span may not contain block elements.
  • Adding a role to a div makes it announce a role but does not give it behaviour. A div with role="button" still needs tabindex, key handlers and focus styling written by hand.
  • Neither is deprecated or discouraged. Both are correct when nothing meaningful applies.
  • They take global attributes like any element, including lang and data-*.

Common mistakes

  • Reaching for div first and only using semantic elements when reminded.
  • Clickable divs.
  • div based headings and list items.
  • Deep wrapper chains left over from a layout approach that no longer applies.
  • Replacing every div with section to look modern, which is worse than leaving them.
  • Using ARIA to patch a div instead of using the element that already exists.

Best practices

  • Choose the meaningful element first; fall back to div or span without guilt.
  • Audit class names: any that name an existing element is a signal.
  • Use CSS grid and flexbox to remove wrapper layers.
  • Read the page with styles off before shipping.
  • Prefer a native element to a div plus ARIA every time.

Practice

  1. Take a nested wrapper chain and remove every level that is not needed for the layout.
  2. List every class name in one of your files and mark those that name an HTML element.
  3. Convert a div based card component to semantic elements without changing the CSS output.
  4. Write down three cases where a div is genuinely the right answer.

Useful resources

Hand picked references for this topic
Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All HTML notes →
HTML

Why Semantic HTML Matters

Two pages can look identical and be worlds apart. Semantic markup is what tells browsers, screen readers and search engines what each part of a page a...

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.