Semantic HTML and Landmarks
The 30-Second Test That Reveals Your HTML Quality
Open your site in Firefox or Safari, then activate Reader View (the little book icon in the address bar). If your content appears cleanly — headings, paragraphs, images, article text — your HTML semantics are solid. If Reader View shows nothing, or mangles your content, your HTML is a pile of meaningless divs.
Reader View works by looking for semantic elements: article, section, h1-h6, p, figure. If it can't find them, it can't extract your content. The same thing happens with screen readers, search engine crawlers, read-it-later apps, and AI summarizers. They all depend on semantic structure.
Semantic HTML isn't just "best practice." It's the interface between your content and every tool that isn't a visual browser.
Think of semantic HTML as road signs. A highway without signs still has lanes and exits — but nobody can navigate it. Signs like "EXIT 42 — Downtown", "SPEED LIMIT 65", and "HOSPITAL NEXT RIGHT" give the road meaning and help travelers find their way. Semantic elements like header, nav, main, article, and footer are road signs for your page. Screen readers use them as shortcuts. Search engines use them to understand content hierarchy. Without them, your page is a highway with no signs — the lanes exist but nobody knows where they go.
The Landmark Elements
HTML5 introduced sectioning elements that define the major regions of a page. Screen readers expose these as landmarks — users can jump directly to any landmark, like using a table of contents.
<body>
<header>
<nav aria-label="Main"><!-- Primary navigation --></nav>
</header>
<main>
<article>
<h1>Article Title</h1>
<section>
<h2>First Section</h2>
<p>Content...</p>
</section>
<section>
<h2>Second Section</h2>
<p>Content...</p>
</section>
</article>
<aside aria-label="Related articles">
<!-- Sidebar content -->
</aside>
</main>
<footer>
<nav aria-label="Footer"><!-- Footer links --></nav>
</footer>
</body>
What Each Landmark Does
| Element | Landmark Role | Purpose |
|---|---|---|
header | banner | Site-wide header (logo, nav, search) — only the top-level one |
nav | navigation | Major navigation blocks |
main | main | Primary content of the page — only one per page |
article | article | Self-contained content (blog post, comment, widget) |
section | region (with label) | Thematic grouping of content |
aside | complementary | Tangentially related content (sidebars, related links) |
footer | contentinfo | Site-wide footer — only the top-level one |
article vs. section vs. div
This is the distinction most developers get wrong:
article — self-contained content that makes sense on its own, even outside the page. Could you syndicate it (put it in an RSS feed, share it independently)? Then it's an article.
<!-- Blog post — makes sense on its own -->
<article>
<h2>Understanding Closures</h2>
<p>Published on <time datetime="2024-01-15">Jan 15</time></p>
<p>Closures are functions that remember their scope...</p>
</article>
<!-- Comment — self-contained, could appear in a feed -->
<article>
<p>Great explanation! This finally clicked for me.</p>
<footer><p>By Alice, 2 hours ago</p></footer>
</article>
section — a thematic grouping of content, typically with a heading. It's a chapter in a book.
<section>
<h2>Prerequisites</h2>
<p>Before starting, make sure you know...</p>
</section>
<section>
<h2>Getting Started</h2>
<p>First, install the dependencies...</p>
</section>
div — no semantic meaning whatsoever. Use it only for styling or layout hooks when no semantic element fits.
<!-- div is correct here — it's a styling wrapper, not a content boundary -->
<div class="card-grid">
<article class="card">...</article>
<article class="card">...</article>
</div>
The decision tree:
- Is it self-contained content that could stand alone? →
article - Is it a thematic group of related content with a heading? →
section - Is it just a grouping for CSS/layout purposes? →
div
The header and footer Elements
These are not just for the page top and bottom. They can exist inside any sectioning element:
<article>
<!-- Article header — not a page-level landmark -->
<header>
<h2>Understanding the Event Loop</h2>
<p>By <a href="/authors/alice">Alice</a> on <time datetime="2024-03-20">March 20, 2024</time></p>
</header>
<p>The event loop is JavaScript's concurrency model...</p>
<!-- Article footer — not a page-level landmark -->
<footer>
<p>Tags: JavaScript, Async, Event Loop</p>
<nav aria-label="Article pagination">
<a href="/prev-article">Previous Article</a>
<a href="/next-article">Next Article</a>
</nav>
</footer>
</article>
Only the header and footer that are direct children of body (or not nested inside article, section, aside, nav) become the page-level landmarks (banner and contentinfo).
ARIA: When HTML Isn't Enough
ARIA (Accessible Rich Internet Applications) adds accessibility information that native HTML can't express:
<!-- Label distinguishes multiple nav landmarks -->
<nav aria-label="Main navigation">...</nav>
<nav aria-label="Footer navigation">...</nav>
<!-- Describe a relationship between elements -->
<input type="email" aria-describedby="email-error">
<p id="email-error" role="alert">Please enter a valid email.</p>
<!-- Live region — screen readers announce changes -->
<div aria-live="polite" aria-atomic="true">
3 items in cart
</div>
The First Rule of ARIA
Don't use ARIA if a native HTML element does the job. ARIA is a repair tool, not a building tool.
<!-- Bad: ARIA role on a div -->
<div role="button" tabindex="0" onclick="handleClick()">Click me</div>
<!-- Good: just use a button -->
<button type="button" onclick="handleClick()">Click me</button>
The button element gives you: keyboard activation (Enter and Space), focus management, correct screen reader announcement, and form submission behavior — for free. The div role="button" gives you none of that. You'd have to add keyboard handlers, focus styles, and all the behavior manually.
Production Scenario: Full Page Structure
Here's the semantic structure of a real course page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Closures — JavaScript Deep Dive — Learn Infinity</title>
</head>
<body>
<a href="#main-content" class="skip-link">Skip to content</a>
<header>
<a href="/" aria-label="Learn Infinity — Home">
<img src="/logo.svg" alt="" width="120" height="32">
</a>
<nav aria-label="Main navigation">
<ul>
<li><a href="/courses" aria-current="page">Courses</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/pricing">Pricing</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<nav aria-label="Breadcrumb">
<ol>
<li><a href="/courses">Courses</a></li>
<li><a href="/courses/frontend-engineering">Frontend Engineering</a></li>
<li><a href="/courses/frontend-engineering/javascript-deep-dive">JavaScript Deep Dive</a></li>
<li aria-current="page">Closures</li>
</ol>
</nav>
<article>
<header>
<h1>Closures and Their Memory Cost</h1>
<p>Published <time datetime="2024-01-15">January 15, 2024</time></p>
</header>
<section aria-label="Introduction">
<h2>The Most Powerful Pattern</h2>
<p>Closures power event handlers, data privacy...</p>
</section>
<section aria-label="Deep explanation">
<h2>What Closures Actually Capture</h2>
<p>Here's where most tutorials get it wrong...</p>
</section>
</article>
<aside aria-label="Related topics">
<h2>Related Topics</h2>
<ul>
<li><a href="/courses/frontend-engineering/javascript-deep-dive/scope-chains">Scope Chains</a></li>
</ul>
</aside>
</main>
<footer>
<nav aria-label="Footer navigation">
<ul>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
<li><a href="/privacy">Privacy</a></li>
</ul>
</nav>
<p><small>Copyright 2024 Learn Infinity</small></p>
</footer>
</body>
</html>
| What developers do | What they should do |
|---|---|
| Using div for everything instead of semantic elements Screen readers expose semantic elements as landmarks. divs are invisible to assistive technology — they provide zero navigation benefit | Use header, nav, main, article, section, aside, footer for page structure |
| Using ARIA roles when native HTML elements exist Native elements have built-in keyboard behavior, focus management, and screen reader support. ARIA only adds the label — you have to rebuild all the behavior yourself | Use the native element first. Only add ARIA when no HTML element provides the needed semantics |
| Multiple main elements on a single page main identifies the primary content. Multiple mains confuse screen readers — which one is the 'real' content? | Use exactly one main element per page (that isn't hidden) |
| Using section without a heading A section without any label is like a chapter without a title. Screen readers announce 'region' with no description, which is useless | Every section should have a heading (h2-h6) or an aria-label |
Challenge: Identify the Semantic Issues
Find all the semantic problems in this HTML:
<body>
<div class="header">
<div class="logo">Site Name</div>
<div class="nav">
<div><a href="/">Home</a></div>
<div><a href="/about">About</a></div>
</div>
</div>
<div class="content">
<div class="sidebar">
<div class="sidebar-title">Related</div>
<div><a href="/topic-1">Topic 1</a></div>
</div>
<div class="post">
<div class="title">My Article</div>
<div class="text">Article content goes here...</div>
</div>
</div>
<div class="footer">
<div>Copyright 2024</div>
</div>
</body>
Show Answer
Here's the corrected version with all issues fixed:
<body>
<a href="#main-content" class="skip-link">Skip to content</a>
<header>
<a href="/">Site Name</a>
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<article>
<h1>My Article</h1>
<p>Article content goes here...</p>
</article>
<aside aria-label="Related topics">
<h2>Related</h2>
<ul>
<li><a href="/topic-1">Topic 1</a></li>
</ul>
</aside>
</main>
<footer>
<p><small>Copyright 2024</small></p>
</footer>
</body>Issues fixed:
div.header→header(creates banner landmark)div.nav→navwitharia-label(creates navigation landmark)- Navigation links wrapped in
ul/li(it's a list of links) div.content→mainwith skip link target (creates main landmark)div.post→article(self-contained content)div.title→h1(page heading, not a styled div)div.text→p(paragraph)div.sidebar→asidewitharia-label(creates complementary landmark)div.sidebar-title→h2(heading for the sidebar section)- Sidebar links wrapped in
ul/li div.footer→footer(creates contentinfo landmark)- Added skip link for keyboard users
- 1Use landmark elements (header, nav, main, article, section, aside, footer) to define page regions — screen readers expose them as navigation shortcuts
- 2One main element per page — it identifies the unique content
- 3article is for self-contained content, section is for thematic grouping, div is for layout only
- 4Don't use ARIA if a native HTML element does the job — native elements come with free keyboard and screen reader support
- 5Every section and aside should have a heading or aria-label to give it an accessible name