The idea
For years, web pages were built from <div>s: generic boxes with names like <div class="header">. They work, but the name is only for humans; the browser has no idea which box is the navigation and which is the main content. Semantic elements say what each part of the page is, and that unlocks real benefits:
- Screen reader users can jump straight to the navigation or the main content ("landmarks").
- Search engines understand which text is the article and which is the footer.
- Teammates read the structure at a glance.
- Browser features such as reader mode work better.
The page landmarks
Almost every site has the same big pieces: a header with the logo and navigation at the top, the main content in the middle, and a footer at the bottom. HTML has an element for each of these, so the browser (and screen readers, and search engines) know exactly which part is which. Here's Toko Kita's page laid out with them:
<header>
<a href="/">Toko Kita</a>
<nav aria-label="Main">
<ul>
<li><a href="/coffee">Coffee</a></li>
<li><a href="/equipment">Equipment</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<main>
<h1>Freshly roasted Indonesian coffee</h1>
<p>Beans from Aceh to Papua, roasted every Monday in Bandung.</p>
</main>
<footer>
<p>© 2024 Toko Kita · <a href="mailto:[email protected]">[email protected]</a></p>
</footer>
| Element | What it is |
|---|---|
<header> | Introductory content: logo, site name, main navigation |
<nav> | A block of major navigation links |
<main> | The page's main content. Exactly one per page |
<footer> | Closing content: copyright, contact, legal links |
© is an HTML entity, a code for a character: ©. Others you'll see are & (&), < (<) and (a space that never breaks a line).
Inside main: article, section, aside
The main area can be broken down further. Toko Kita has a coffee journal, a small blog. Each post stands on its own, has sections with their own headings, and the page has a box of related links on the side. Each of those has its own element:
<main>
<h1>Coffee journal</h1>
<article>
<h2>Why we roast on Mondays</h2>
<p>Published <time datetime="2024-10-07">7 October 2024</time></p>
<p>Coffee tastes best a few days after roasting...</p>
<section>
<h3>The resting period</h3>
<p>Freshly roasted beans release carbon dioxide for several days...</p>
</section>
<section>
<h3>Shipping schedule</h3>
<p>Monday roasts ship on Wednesday, arriving at their best...</p>
</section>
</article>
<aside>
<h2>Related</h2>
<ul><li><a href="/journal/grind-size">Choosing a grind size</a></li></ul>
</aside>
</main>
<article>: a self-contained piece that would make sense on its own: a blog post, a product card, a review, a news item.<section>: a thematic part of something larger, with its own heading.<aside>: content related to, but separate from, the main content: related links, a sidebar, a tip box.<time datetime="2024-10-07">: a date or time in a machine-readable format, while showing any human-friendly text.
A useful test: if it could be shared or syndicated on its own, it's an article. If it's a chapter of something, it's a section. If it has no meaning of its own and just groups things for styling, it's a <div>.
<div> and <span> still have a place
Semantic elements don't replace <div> (a generic block) and <span> (a generic inline piece of text). Use them when no element describes the meaning, typically as hooks for CSS:
<article class="product-card">
<h3>Arabica Gayo</h3>
<div class="price-row">
<span class="price">Rp 95.000</span>
<span class="unit">/ 250 g</span>
</div>
</article>
The rule: reach for a semantic element first, and fall back to <div>/<span> only when nothing fits.
Build the page from landmarks (header, nav, main, footer) and give the main content meaningful parts (article, section, aside, time). Use div and span only when no element describes the meaning.
Headings give the outline
Every <section> and <article> should start with a heading, and heading levels should follow the structure: an <h1> for the page, <h2> for its main parts, <h3> inside those. Screen reader users navigate by headings more than by anything else, so the outline is the page's table of contents.
Why this matters for clean code
Semantic HTML is self-documenting code. Compare reading <div class="wrapper"><div class="top"><div class="links"> with <header><nav>: the second needs no comment. It also means fewer classes and less CSS to target the main areas, and accessibility that comes built in rather than bolted on.
Recap
- Landmarks:
<header>,<nav>,<main>(exactly one),<footer>. <article>for self-contained content,<section>for parts with a heading,<aside>for related extras.<time datetime="YYYY-MM-DD">for dates.<div>and<span>when no semantic element fits.- Headings form the outline: one
<h1>, then<h2>,<h3>in order.