Semantic HTML: how to structure more accessible pages
Tags like header, nav, main, and article aren't just visual organization — they define what each part of the page means to screen readers, crawlers, and SEO.
I opened DevTools on a client's landing page last week and found a wall of <div> elements. Div with class header, div with class nav, div with class content, div with class footer. Everything rendering perfectly in Chrome. No screen reader could navigate it properly. No crawler could distinguish editorial content from the menu. That's div-soup — and it's far more common than it should be.
Semantic HTML is the practice of using the right elements for what they represent. Not about CSS, not about JavaScript. About the meaning you communicate to the browser, to Google, and to any assistive technology trying to make sense of your page.
Why div and span are not enough
<div> and <span> are meaningless elements. They exist to group content for styling or scripting purposes — nothing else. The browser, screen reader, and crawler know a <div> contains something, but have no idea what.
When you use <nav>, you're saying: this is navigation. When you use <main>, you're saying: this is the primary content of the page. When you use <article>, you're saying: this is a self-contained unit of content that makes sense out of context.
The difference feels small until you open a screen reader like NVDA or VoiceOver. Blind users navigate by landmarks — they press a key to jump directly to <main>, or list all <nav> elements on the page. With div-soup, that shortcut simply doesn't exist.
The tags that handle most cases
HTML5 added a set of structural elements that cover virtually any modern site layout. Most developers know the names; few use them correctly.
<header> and <footer>
These can appear inside <body> (page header/footer) or inside <article> and <section> (section header/footer). They are not unique elements per page — you can have multiple <footer> elements, each with a different scope.
<body>
<header>
<a href="/">Logo</a>
<nav>...</nav>
</header>
<main>
<article>
<header>
<h1>Article title</h1>
<time datetime="2026-06-13">June 13, 2026</time>
</header>
<!-- content -->
<footer>
<p>Author: Rafael Duarte</p>
</footer>
</article>
</main>
<footer>
<p>© 2026 Quick Tools</p>
</footer>
</body>
<nav>
For navigation blocks — main menu, breadcrumbs, pagination. No aria-label needed if there's only one on the page. If you have more than one <nav>, add aria-label="Main menu" and aria-label="Article navigation" to distinguish them.
<main>
Should exist exactly once per page. Contains the unique content of that page — what differentiates it from all others. Does not go inside <header>, <footer>, <aside>, or <nav>.
<article> vs <section>
This is the most common source of confusion. The practical test:
<article>: would this make sense as an independent post in an RSS feed? Yes → use<article>. Blog posts, product cards, comments, weather widgets.<section>: a thematic group of content that doesn't stand alone outside the page? Use<section>.
A blog post is an <article>. The chapters inside that post are <section> elements. The comments below are multiple <article> elements inside a <section>.
<main>
<article>
<h1>Semantic HTML: structure that matters</h1>
<section>
<h2>Why div isn't enough</h2>
<p>...</p>
</section>
<section>
<h2>The key tags</h2>
<p>...</p>
</section>
<section aria-label="Comments">
<h2>Comments</h2>
<article>
<p><strong>Jane:</strong> Great post!</p>
</article>
</section>
</article>
</main>
<aside>
Related but dispensable content — sidebar, "You might also like" boxes, footnotes, ads. If you remove the <aside>, the main content should still make complete sense.
Heading hierarchy matters as much as the tags
Semantic tags structure the page, but headings structure the content. The rule is simple: exactly one <h1> per page, and headings should not skip levels.
That means: don't use <h3> after <h1> just because you want smaller text. Use CSS for size, use headings for hierarchy.
<!-- wrong -->
<h1>Main title</h1>
<h3>Subtitle (skipped h2)</h3>
<!-- right -->
<h1>Main title</h1>
<h2>Subtitle</h2>
<h3>Sub-subtitle</h3>
Screen readers generate a page outline from headings. When you skip levels, that outline breaks — and users who depend on it lose the page's navigable structure.
If you're still learning how the browser interprets and renders HTML before styles even enter the picture, the post How a web page works covers the full cycle from DNS lookup to page paint.
The real SEO impact
Google is not a screen reader, but it uses semantic structure in a similar way. <main> signals where the primary content is. <article> suggests editorial content. <h1>–<h6> build the thematic skeleton of the page.
The effect isn't magic. Correct semantics doesn't replace relevant content, quality backlinks, or page speed. But it removes noise — it helps the crawler understand what is content and what is UI. On large sites, this affects crawl budget.
One practical point: Google uses the <title> and the first <h1> to understand the page topic. If those two are misaligned — or if you have multiple <h1> elements because a framework injected one in the header and another in main — you're sending a contradictory signal.
ARIA: when to use and when not to
ARIA (Accessible Rich Internet Applications) are attributes that add semantics where native HTML falls short — custom components like role="dialog" or role="tabpanel".
Rule number one of ARIA: don't use ARIA where native HTML works. If you can use <button>, use <button>. Don't create <div role="button"> — you'll need to manually implement the keyboard behavior, focus management, and state announcements that <button> gives you for free.
<!-- bad: div pretending to be a button -->
<div class="btn" role="button" onclick="...">Submit</div>
<!-- good: native element with all semantics built in -->
<button type="submit">Submit</button>
A native <button> is keyboard-focusable, activatable via Enter and Space, correctly announced by screen readers, and automatically gets :focus styles. The <div> version needs about 30 lines of JavaScript to reach the same place.
Checking your structure before deploying
After building the semantic structure, the Meta Tag Generator helps you verify what Google will read in your page's <head> — title, description, og:image, canonical — which complement the body semantics.
For heading outlines and landmarks, the WAVE plugin for Chrome or the Accessibility panel in Firefox DevTools shows the structure as a screen reader sees it. Worth checking before going to production.
Frequently asked questions
What's the difference between <section> and <div>?
<div> has no semantic meaning — it's a generic container for visual grouping or scripting. <section> indicates a thematic section of the document and typically includes a heading. Screen readers can list sections as landmarks; divs are invisible to that type of navigation. The practical rule: if you don't have a heading to put inside it, a <div> is probably more honest.
Does semantic HTML actually affect SEO in practice?
Yes, but indirectly and hard to isolate. Google states it uses HTML structure to understand content — <article>, <main>, well-hierarchized headings. What's concretely documented: Google uses <h1> as a topic signal; rich results for articles depend on structured data that complements HTML semantics; markup errors like multiple <h1> elements are flagged in Search Console. The impact is more about clarity than direct ranking.
Can I have more than one <main> on the page?
No. The HTML spec states there can only be one visible <main> per page. You can have multiple <main> elements if extras have the hidden attribute, but only one should be active and visible at a time. SPA frameworks that build complex layouts sometimes violate this rule unintentionally — worth checking in DevTools.
Is <header> inside <article> different from the page <header>?
Yes. <header> is scoped to its nearest ancestor — if it's inside an <article> or <section>, it's the header of that element, not the page. The <header> at the <body> level is the page header. Screen readers distinguish between the two and announce the context correctly.
Structure is communication
Semantic HTML isn't formalism. It's the difference between a page that any agent — human, crawler, screen reader, LLM scraping content — can understand without having to infer meaning from visual appearance.
Div-soup works in Chrome. Works in Firefox. Doesn't work for users who navigate by keyboard, doesn't work for high-contrast mode, doesn't work for screen reader users. Those users exist — and in enterprise projects, accessibility is a legal requirement in many countries.
The effort is low: swapping <div class="header"> for the right elements takes under an hour on an existing project. The payoff is structure that works for everyone, cleaner SEO signals, and code that any developer can understand without reading the CSS first.
- 01 What DevOps Actually Is Beyond the Tools DevOps isn't a pipeline or a job title. It's shared ownership between the people who write code and the people who run it in production — and why most teams get it wrong.
- 02 VPS, VPC, and Dedicated Server: What's the Difference and When to Use Each VPS, VPC, and dedicated server appear side by side on every hosting comparison page — but they mean different things. Here's where the money goes and how to decide.