Français

Div soup, good intentions paving the road to digital hell

Table of contents

The invisible symptom

Open the developer tools on any website. Expand the DOM. Count the <div>s.

On an average site, you'll find hundreds. Not necessarily replacing semantic elements — most projects use a <header>, a few <button>s, a <form>. The problem is more insidious: it's the <div>s that pile up around them. Three levels of wrappers to centre a button. A <div class="content-wrapper"> doubling a <main> that's already there. A <div class="form-group"> where a <fieldset> would do. <div>s nested inside <div>s nested inside <div>s, carrying CSS classes that the semantic elements could have carried themselves.

Visually, everything works. The colours are there, the layout holds, the animations run. The client is happy. The sighted user notices nothing.

But the <div> says nothing. It's an empty container — no role, no semantics, no meaning. To a screen reader, a <div> doesn't exist. To a search engine, it's noise. To the browser, it's one more node to build, to paint, to recycle.

This article details what every unnecessary <div> costs — in accessibility, in performance, in SEO, in GEO. And it shows which HTML elements already exist to do the job.

The HTML that already exists

HTML has over 100 elements. Most projects use about ten — and wrap each one in <div>s that add nothing. Here are the elements that <div> most often replaces or smothers — and what is lost each time.

Page structure

Semantic elements for page structure
Instead of…Use…What you gain
<div class="header"><header>The screen reader jumps straight to the header
<div class="nav"><nav>Identifiable navigation, listed automatically
<div class="main"><main>Main content, one per page
<div class="footer"><footer>Footer information
<div class="sidebar"><aside>Complementary content that can be removed without losing information
<div class="section"><section>Thematic region (a landmark only if it has an accessible name)
<div class="article"><article>Self-contained, redistributable content

Most of these elements create landmarks, waypoints that the screen reader announces and the user can reach with a single keyboard shortcut. Three nuances: <header> and <footer> are only landmarks at page level (not nested inside an <article> or a <section>), <section> only becomes one if it carries an accessible name (aria-label or aria-labelledby), and <article> isn't one at all — its value lies elsewhere: it delimits self-contained content that assistive technologies know how to announce. Every <div> that replaces one removes a waypoint. And every <div> that wraps one adds an empty node between the user and the information.

Interactive elements

Semantic interactive elements
Instead of…Use…What you gain
<div onclick="..."><button>Keyboard focus, announced role, native Enter + Space
<div class="link"><a href="...">Keyboard focus, announced role, browser history
<div class="input"><input>Native validation, autocomplete, specialised types
<div class="select"><select>Native dropdown, keyboard support, mobile optimised

A <div onclick> doesn't receive keyboard focus. It isn't announced as a button. It doesn't respond to Enter or Space. To make it functional, you need role="button", tabindex="0", a keydown handler, and a focus style — exactly the kind of ARIA tinkering best avoided. Four attributes and JavaScript to reinvent what <button> does in six characters.

The forgotten elements

Often-forgotten HTML elements
ElementWhat it doesWhat you find instead
<details> / <summary>Native accordion, no JS neededA <div> + JS + ARIA
<dialog>Native modal, built-in focus trapA <div> + overlay + JS + ARIA
<figure> / <figcaption>Image or block with associated captionA <div> + a disconnected <p>
<time>Machine-readable date/timeA <span> with no semantics
<address>Contact informationA <div> or a <p>
<mark>Highlighted text (search result)A <span> with CSS
<fieldset> / <legend>Field group with labelNested <div>s
<blockquote> / <cite>Quote with attributionAn italicised <div>
<abbr>Abbreviation with full titleNothing, or a <span> with a title
<code> / <pre>Source codeA <div> with a monospace font
<dl> / <dt> / <dd>Definition list, glossary, key-value summary<div>s with <span>s

Each of these elements carries semantics that the browser, screen reader, search engine and LLM exploit. Every <div> that replaces them erases those semantics.

Anatomy of a soup

Take a typical page: a header, navigation, content with a heading, a footer. The semantic HTML is there — but buried.

real-world.html
<!-- What most codebases actually look like -->
<div class="page-wrapper">
  <div class="top-container">
    <header>
      <div class="header-inner">
        <div class="logo-wrapper">
          <a href="/">Acme</a>
        </div>
        <div class="nav-wrapper">
          <nav>
            <div class="nav-inner">
              <div class="menu-item"><a href="/">Home</a></div>
              <div class="menu-item"><a href="/about">About</a></div>
            </div>
          </nav>
        </div>
      </div>
    </header>
  </div>
  <div class="content-container">
    <div class="content-inner">
      <main>
        <div class="title-wrapper">
          <h1>Welcome</h1>
        </div>
        <div class="text-block">
          <p>First paragraph.</p>
        </div>
        <div class="text-block">
          <p>Second paragraph.</p>
        </div>
      </main>
    </div>
  </div>
  <div class="footer-container">
    <footer>
      <div class="footer-inner">
        <p>© 2026</p>
      </div>
    </footer>
  </div>
</div>
semantic.html
<!-- The same page, without the noise -->
<header>
  <a href="/">Acme</a>
  <nav>
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/about">About</a></li>
    </ul>
  </nav>
</header>
<main>
  <h1>Welcome</h1>
  <p>First paragraph.</p>
  <p>Second paragraph.</p>
</main>
<footer>
  <p>© 2026</p>
</footer>

The first example isn't a caricature. It's what most projects produce — semantic elements drowned in layers of CSS wrappers. The <header> is there, the <main> is there, the <h1> is there. But between the user and those waypoints, there are 15 <div> nodes that say nothing.

The second does the same thing in 10 lines. Zero <div>s. The semantic elements carry their own styles.

What this changes for a screen reader

Modern browsers are smart: they filter semantics-free <div>s out of the accessibility tree to reduce noise. A <div class="wrapper"> around a <button> doesn't stop the screen reader from finding the button.

But if the browser ignores them, that's precisely because they serve no purpose. Everything a <div> wrapper does — carry a class, receive a display: flex, define a margin — a semantic element does too. A <nav class="main-nav"> accepts the same CSS properties as a <div class="nav-wrapper">. A <header> can be a flex container just like a <div class="header-container">. The browser sees no difference on the rendering side — but it sees a huge difference on the accessibility side.

And that filter doesn't solve the deeper problem. What's missing in a <div> soup isn't the extra nodes — it's the missing waypoints.

71.6% of screen reader users navigate by headings. 31.8% frequently use landmarks. These are the two primary methods for orienting within a page. I go into detail in Screen readers don't read like you.

When a <div class="section-title"> replaces an <h2>, a heading disappears from the navigation list. When a <div class="sidebar"> replaces an <aside>, a landmark ceases to exist. The user loses a shortcut to the information — and there's no way to know without inspecting the code.

A 2007 study of 100 blind users measured that they lose an average of 30.4% of their time to frustrating situations, all causes combined, with confusing page structure as the leading one — missing waypoints, mislabelled content, unpredictable layouts.

You can see the accessibility tree yourself: in Chrome, open DevTools → Elements tab → Accessibility pane. It's an X-ray of what your HTML actually says — regardless of what it shows.

What it costs

In practice, few sites are built entirely out of <div>s. Most use some semantic elements — a <header> here, a <button> there. The problem is more insidious: it's the <div>s that accumulate around, inside and between the useful elements. Three levels of wrappers for a button. A <div class="form-group"> where a <fieldset> would do. A <div class="content"> doubling a <main> that's already there.

The site doesn't collapse. It works. But every unnecessary <div> dilutes the semantics, bloats the DOM and adds noise — on four fronts.

Accessibility

A screen reader navigates by waypoints: headings, landmarks, links, buttons. In a <div> soup, there are no waypoints. The user must traverse every DOM node, one by one, top to bottom. On a 200-node page, it's the equivalent of reading a book with no table of contents, no chapters and no page numbers.

Interactive elements built from <div>s are invisible to the keyboard. A user who can't use a mouse — and there are many — simply cannot interact with your site.

Performance

Every unnecessary <div> is an extra node in the DOM. The deeper the DOM, the longer the browser takes to calculate styles, layout and paint. Google Lighthouse triggers a warning above 800 elements and an error above 1,400, with a recommended maximum depth of 32 levels. According to the Web Almanac 2022, the 90th percentile of web pages is already approaching 2,000 elements (1,832 on mobile, 2,023 on desktop), with a median of 653.

And every hand-rolled interactive <div> ships JavaScript that the native element wouldn't have needed. A native <dialog> opened with showModal() handles the focus trap on its own. A <div> modal needs a script, an overlay and several event handlers. More code, more weight, more bugs.

SEO

Google uses HTML semantics to understand a page's structure. An <h2> is a heading. A <nav> is navigation. An <article> is self-contained content. A <div> is nothing — Google can work without semantics, but semantic HTML makes its job easier.

Featured snippets, rich results, position-zero extracts — all rely on structure that Google can interpret unambiguously. A clear heading hierarchy, lists, tables. The more explicit the structure, the more material Google has to generate those results.

GEO

LLMs don't rank pages — they select passages to cite. And to slice a page into passages, they rely on structure: headings, sections, articles, lists. Without those markers, the LLM sees an undifferentiated stream of text — harder to segment, harder to cite, easier to ignore.

An <h2> delimits a topic. A <ul> structures an enumeration. An <article> isolates self-contained content. A <div> does none of that. And when the LLM must choose between a structured page and a <div> soup, the outcome is predictable.

I go into detail in How GEO forces web accessibility: generative engines favour content that is structured, sourced and machine-readable. Div soup is the exact opposite.

Four axes, one symptom. Div soup isn't an accessibility problem. It's a quality problem that manifests everywhere.

To see what this looks like in practice, I took a real product card from an e-commerce site — 87 elements including 27 <div>s, 17 <span>s, 5 <i>s, and only 6 semantic tags — and rewrote it without a single <div>. Same rendering, zero visual compromise. The step-by-step breakdown is in Anatomy of a product card.

So when should you use a <div>?

One case is in the specification: inside a <dl>, a <div> can group a <dt> / <dd> pair. This is the only place where <div> provides a structure that HTML doesn't offer otherwise. The GOV.UK Design System uses it in its Summary List component — and it's one of the rare examples where <div> is the right answer.

Beyond that, every <div> is an admission: I don't know how to do it any other way. Not "there's nothing else" — because there's always something. A <header>, a <main>, a <footer>, a <section>, a <fieldset>, a <ul>, a <figure>. Over 100 elements, each with a role, a behaviour and semantics. The right HTML element exists — you just have to look for it.

The <div> isn't an enemy. It's a shortcut. And every shortcut has a cost — in accessibility, in performance, in SEO, in GEO. That cost, you now know.

Sources