HTML and CSS course Β· Module 10: Accessibility (a11y)

Semantic HTML and Accessibility

7 min read
In this lesson7

Imagine a blind pilgrim entering a temple where no chamber has an inscription above its entrance. They hear their own footsteps echo, but they cannot tell whether they are standing in the prayer hall or in a storeroom. A screen reader user feels exactly the same on a page built entirely from <div> elements. In Ancient Egypt, hieroglyphs had strictly defined meanings - each symbol served a specific function. It is similar with semantic HTML: each tag carries information about the role and meaning of the content, which is crucial for assistive technologies.

Why Is Semantics So Important?

Screen readers do not "see" the page - they read its HTML structure. When you use <div> for everything, the reader does not know what is navigation, what is a heading, and what is the main content. Compare two versions of the same fragment of the museum page - first the "div soup", then the semantic version:

1<!-- BAD - "div soup" -->
2<div class="header">
3    <div class="nav">
4        <div class="nav-item">Home</div>
5        <div class="nav-item">About Us</div>
6    </div>
7</div>
8<div class="content">
9    <div class="title">Welcome to the museum</div>
10    <div class="text">Exhibition description...</div>
11</div>
12
13<!-- GOOD - semantic HTML -->
14<header>
15    <nav aria-label="Main navigation">
16        <ul>
17            <li><a href="/">Home</a></li>
18            <li><a href="/about">About Us</a></li>
19        </ul>
20    </nav>
21</header>
22<main>
23    <h1>Welcome to the museum</h1>
24    <p>Exhibition description...</p>
25</main>

Both versions can look identical, because CSS can make a <div> resemble anything. The difference is invisible to the eye but huge for the reader: in the second version it announces a navigation with a list of two links, and the user can jump straight to the main content with a single keyboard shortcut. The content did not change - only the tags did, and the plain labels in the menu became real links.

Key Semantic Tags

Sectioning Elements

Here are seven tags from which you will build the skeleton of almost any page. Treat them like inscriptions above chamber entrances - each one says what is inside:

1<header>  <!-- Page or section header -->
2<nav>     <!-- Navigation -->
3<main>    <!-- Main page content (only one per page!) -->
4<article> <!-- Standalone content (post, article) -->
5<section> <!-- Thematic content group -->
6<aside>   <!-- Supplementary content (sidebar) -->
7<footer>  <!-- Page or section footer -->

Notice the comment next to <main>: a page has exactly one visible <main> element (the HTML specification allows more only when the extra ones are hidden with the hidden attribute). <header> and <footer> are different - they can appear many times, for example inside every <article>.

Heading Hierarchy

Headings create the document structure. Screen readers let users navigate by headings - in the NVDA screen reader the H key jumps to the next one - so many users first "skim" a page by its headings alone, like a pilgrim reading only the tablets above the chambers. That is why their hierarchy must be correct:

1<!-- BAD - skipped h2 level -->
2<h1>Egyptian Museum</h1>
3<h3>Permanent Exhibitions</h3>     <!-- Should be h2! -->
4<h4>Treasures of the Pharaohs</h4> <!-- Should be h3! -->
5
6<!-- GOOD - correct hierarchy -->
7<h1>Egyptian Museum</h1>
8<h2>Permanent Exhibitions</h2>
9<h3>Treasures of the Pharaohs</h3>
10<h3>Royal Mummies</h3>
11<h2>Temporary Exhibitions</h2>
12<h3>Gold of Tutankhamun</h3>

A heading level describes a place in the hierarchy, not the size of the letters. If an <h2> looks too big to you, make it smaller in CSS, but do not jump to <h3> - the reader would then conclude that a level is missing from the document. The order is always the same: from <h1> (the page title), through <h2> and <h3>, down to <h6>.

Lists

Lists carry meaning too. When navigation links sit inside a <ul>, the reader announces the number of items before the user starts listening to them. A definition list <dl>, in turn, pairs a term (<dt>) with its explanation (<dd>), like a scribe's dictionary:

1<!-- Navigation as a list - the reader will say "list, 4 items" -->
2<nav>
3    <ul>
4        <li><a href="/">Home</a></li>
5        <li><a href="/exhibitions">Exhibitions</a></li>
6        <li><a href="/tickets">Tickets</a></li>
7        <li><a href="/contact">Contact</a></li>
8    </ul>
9</nav>
10
11<!-- Definition list -->
12<dl>
13    <dt>Scarab</dt>
14    <dd>Sacred beetle symbolizing rebirth</dd>
15    <dt>Ankh</dt>
16    <dd>Symbol of eternal life</dd>
17</dl>

You can remove the bullets next to the links with a single CSS rule - appearance is the job of the stylesheet, and meaning is the job of HTML.

Landmark Roles

Semantic HTML tags automatically create so-called landmarks (orientation points), which screen reader users can quickly navigate:

HTML TagLandmark RoleDescription
<header>bannerPage header
<nav>navigationNavigation
<main>mainMain content
<aside>complementarySupplementary content
<footer>contentinfoFooter
<section>region*Thematic section
<form>form*Form

*Requires an aria-label or aria-labelledby attribute.

The table also shows the typical order of landmarks from the top of a page: banner, navigation, main, complementary and contentinfo. There is one nuance: <header> and <footer> get the banner and contentinfo roles only when they are not nested inside <article>, <aside>, <main>, <nav> or <section>. These roles are built in, so do not add role="navigation" to a <nav> - it just repeats the same information.

Practical Example

Let's combine everything into a single museum page. Read the code from top to bottom and try to point out every landmark from the table above:

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <title>Ancient Egypt Museum</title>
6</head>
7<body>
8    <header>
9        <h1>Ancient Egypt Museum</h1>
10        <nav aria-label="Main navigation">
11            <ul>
12                <li><a href="/">Home</a></li>
13                <li><a href="/exhibitions">Exhibitions</a></li>
14            </ul>
15        </nav>
16    </header>
17
18    <main>
19        <article>
20            <h2>Exhibition: Treasures of Tutankhamun</h2>
21            <p>Discover incredible artifacts...</p>
22            <figure>
23                <img src="mask.jpg" alt="Golden death mask of Tutankhamun">
24                <figcaption>Death mask of Tutankhamun, c. 1323 BCE.</figcaption>
25            </figure>
26        </article>
27    </main>
28
29    <aside aria-label="Additional information">
30        <h2>Opening Hours</h2>
31        <p>Mon-Fri: 9:00-17:00</p>
32    </aside>
33
34    <footer>
35        <p>Ancient Egypt Museum 2024</p>
36    </footer>
37</body>
38</html>

There is not a single <div> here, and nothing is missing. The <aside> got an aria-label, so the reader will introduce it as "Additional information", and the <figure> with its <figcaption> ties the photo of the mask to its caption.

Common Semantic Mistakes

Finally, three traps that almost every beginner falls into. Each pair shows the wrong version and the correct one:

1<!-- BAD: div instead of button -->
2<div onclick="submit()">Submit</div>
3
4<!-- GOOD: native button -->
5<button onclick="submit()">Submit</button>
6
7<!-- BAD: span as heading -->
8<span class="big-text">Important Title</span>
9
10<!-- GOOD: proper heading -->
11<h2>Important Title</h2>
12
13<!-- BAD: br for creating spacing -->
14<br><br><br>
15
16<!-- GOOD: CSS margin/padding -->
17<p style="margin-top: 2rem;">Text with spacing</p>

A <div> with onclick will not receive keyboard focus and will not react to Enter or Space, while a native <button> does all of that on its own. A <span> pretending to be a heading will not appear in the reader's list of headings, and a series of <br> tags is just empty lines to the reader, not spacing. Notice that none of the correct versions needs a single ARIA attribute. My advice: before you reach for a <div>, ask whether HTML already has an element with that meaning - it usually does, and that element is the best choice.

Validating Semantics

You can check the semantics of your page using:

  • W3C Validator - checks HTML correctness
  • WAVE - analyzes page accessibility
  • Lighthouse - accessibility audit in Chrome DevTools

You will get to know them better in the lesson on accessibility testing, and in the next lessons this semantic skeleton will become the basis of keyboard navigation.

Semantic HTML is the foundation of accessibility - just as solid pyramid foundations ensure its durability for millennia, so correct semantics ensures that the page will be accessible to all users. Every HTML element should match its role: a heading should be a heading, navigation should be navigation, and a button should be a button.

Practice

In the editor below you will find a semantic museum page. Replace one of the tags with a <div> and think about what information the screen reader has just lost:

Code for this lesson: index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>Ancient Egypt Museum - Semantic HTML</title>
7    <link rel="stylesheet" href="style.css">
8</head>
9<body>
10    <header>
11        <h1>Ancient Egypt Museum</h1>
12        <nav aria-label="Main navigation">
13            <ul>
14                <li><a href="#exhibitions">Exhibitions</a></li>
15                <li><a href="#artifacts">Artifacts</a></li>
16                <li><a href="#visit">Visit us</a></li>
17            </ul>
18        </nav>
19    </header>
20
21    <main>
22        <section id="exhibitions" aria-labelledby="ex-title">
23            <h2 id="ex-title">Current exhibitions</h2>
24
25            <article>
26                <h3>Treasures of Tutankhamun</h3>
27                <p>Discover extraordinary artifacts from the tomb of the young pharaoh,
28                   discovered by Howard Carter in 1922.</p>
29                <figure>
30                    <img src="https://placehold.co/400x250/d4af37/1a1a2e?text=Tutankhamun+Mask"
31                         alt="Golden death mask of Pharaoh Tutankhamun">
32                    <figcaption>Death mask of Tutankhamun, c. 1323 BCE</figcaption>
33                </figure>
34            </article>
35
36            <article>
37                <h3>Royal Mummies</h3>
38                <p>Discover the secrets of mummification in Ancient Egypt.</p>
39            </article>
40        </section>
41
42        <section id="artifacts" aria-labelledby="art-title">
43            <h2 id="art-title">Artifacts collection</h2>
44            <dl>
45                <dt>Scarab</dt>
46                <dd>Sacred beetle symbolizing rebirth and creation</dd>
47                <dt>Ankh</dt>
48                <dd>Symbol of eternal life, worn by pharaohs</dd>
49                <dt>Eye of Horus</dt>
50                <dd>Symbol of protection, health, and royal power</dd>
51            </dl>
52        </section>
53    </main>
54
55    <aside aria-label="Additional information">
56        <h2>Opening hours</h2>
57        <p>Mon-Fri: 9:00-17:00</p>
58        <p>Sat-Sun: 10:00-18:00</p>
59    </aside>
60
61    <footer>
62        <p>Ancient Egypt Museum &copy; 2024</p>
63        <nav aria-label="Footer links">
64            <ul>
65                <li><a href="/privacy">Privacy policy</a></li>
66                <li><a href="/accessibility">Accessibility statement</a></li>
67            </ul>
68        </nav>
69    </footer>
70</body>
71</html>

Remember: a semantic tag is the inscription above a chamber entrance - thanks to it, every visitor knows where the corridor leads, even without seeing the walls.

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. How many <main> elements can a single HTML page contain?

  2. 2. Why is a correct heading hierarchy (h1-h6) important for accessibility?

Hands-on tasks in the game

  • Code editor

    Replace divs with semantic HTML tags: header, nav (with aria-label), main, article, aside, and footer.

  • Vertical ordering

    Arrange HTML headings from the most important to the least important:

Useful articles