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.
-
HTML Basics
- What is HTML: The Structure Layer of Every Web Page
- HTML Document Structure: DOCTYPE, html, head and body
- Elements, Tags and Attributes: The Vocabulary of HTML
- HTML Comments: Notes That Ship With Your Code
- Block Level and Inline Elements
- Writing and Running Your First HTML Page
- How a Browser Turns Markup Into a Page
- Text and Formatting
- Links and Navigation
- Images and Media
- Lists
- Tables
-
Forms
- Form Structure: form, action and method
- Input Types: Text, Email, Number, Date and the Rest
- Labels: The Most Important Element in a Form
- Checkboxes, Radio Buttons and Grouping
- select, option, optgroup and datalist
- textarea, File Uploads and Hidden Fields
- Buttons: submit, reset and button
- Built In Form Validation
- GET or POST: What Happens When a Form Is Submitted
- Semantic HTML
- HTML5 Features
- Head and Metadata
- HTML with CSS
- HTML with JavaScript
- Accessibility
-
HTML SEO
- How Google Works: Crawling, Indexing and Ranking
- SEO Friendly HTML Structure
- Titles and Descriptions That Earn Clicks
- Headings and Content Structure for Search
- Internal Linking and Anchor Text
- robots.txt and XML Sitemaps
- Canonical URLs and Duplicate Content
- Structured Data and JSON-LD
- Image SEO
- Core Web Vitals and Mobile Friendliness
- DevTools and Debugging
- Editor Productivity
- HTML Best Practices
- HTML Projects
- Advanced Projects
- Practice and Exams
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.
div | span | |
|---|---|---|
| Display | Block | Inline |
| Meaning | None | None |
| May contain | Block and inline | Inline only |
| Typical use | Layout wrapper, grid or flex container | Styling 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 wrote | You 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
divwhose class name matches an existing element name. - More than three or four wrapper levels with no content between them.
- A page with no
main, nonav, 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.
spanmay not contain block elements.- Adding a
roleto adivmakes it announce a role but does not give it behaviour. Adivwithrole="button"still needstabindex, 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
langanddata-*.
Common mistakes
- Reaching for
divfirst and only using semantic elements when reminded. - Clickable divs.
divbased headings and list items.- Deep wrapper chains left over from a layout approach that no longer applies.
- Replacing every
divwithsectionto look modern, which is worse than leaving them. - Using ARIA to patch a
divinstead of using the element that already exists.
Best practices
- Choose the meaningful element first; fall back to
divorspanwithout 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
divplus ARIA every time.
Practice
- Take a nested wrapper chain and remove every level that is not needed for the layout.
- List every class name in one of your files and mark those that name an HTML element.
- Convert a
divbased card component to semantic elements without changing the CSS output. - Write down three cases where a
divis genuinely the right answer.