Skip to content

Semantic HTML and Landmarks

beginner14 min read

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.

Mental Model

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

ElementLandmark RolePurpose
headerbannerSite-wide header (logo, nav, search) — only the top-level one
navnavigationMajor navigation blocks
mainmainPrimary content of the page — only one per page
articlearticleSelf-contained content (blog post, comment, widget)
sectionregion (with label)Thematic grouping of content
asidecomplementaryTangentially related content (sidebars, related links)
footercontentinfoSite-wide footer — only the top-level one
Quiz
How many main elements should a page have?

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:

  1. Is it self-contained content that could stand alone? → article
  2. Is it a thematic group of related content with a heading? → section
  3. Is it just a grouping for CSS/layout purposes? → div
Quiz
Which element should you use to wrap a blog post's comment?

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).

Quiz
A footer element inside an article — is it a page-level landmark?

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.

Quiz
When should you use ARIA roles and attributes?

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>
Execution Trace
Screen reader enters page
Announces page title: 'Closures — JavaScript Deep Dive — Learn Infinity'
Title comes from the title element in head
List landmarks
Banner, Main Navigation, Breadcrumb, Main, Article, Related Topics, Footer Navigation, Content Info
User can jump to any landmark directly
Jump to main
Skip link or landmark shortcut takes user to main content
Bypasses all navigation
Navigate by headings
H key cycles through: 'Closures and Their Memory Cost' (h1), 'The Most Powerful Pattern' (h2), 'What Closures Actually Capture' (h2)
Heading hierarchy provides document outline
What developers doWhat 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:

  1. div.headerheader (creates banner landmark)
  2. div.navnav with aria-label (creates navigation landmark)
  3. Navigation links wrapped in ul/li (it's a list of links)
  4. div.contentmain with skip link target (creates main landmark)
  5. div.postarticle (self-contained content)
  6. div.titleh1 (page heading, not a styled div)
  7. div.textp (paragraph)
  8. div.sidebaraside with aria-label (creates complementary landmark)
  9. div.sidebar-titleh2 (heading for the sidebar section)
  10. Sidebar links wrapped in ul/li
  11. div.footerfooter (creates contentinfo landmark)
  12. Added skip link for keyboard users
Key Rules
  1. 1Use landmark elements (header, nav, main, article, section, aside, footer) to define page regions — screen readers expose them as navigation shortcuts
  2. 2One main element per page — it identifies the unique content
  3. 3article is for self-contained content, section is for thematic grouping, div is for layout only
  4. 4Don't use ARIA if a native HTML element does the job — native elements come with free keyboard and screen reader support
  5. 5Every section and aside should have a heading or aria-label to give it an accessible name