Lesson 13 / 25
Semantic Section Tags
How header, navigation, main content, and footer elements correspond to landmark roles, naming sections, and where a meaningless container belongs.
Contents
The previous topic built the document’s skeleton: headings, text, lists, links, tables. None of these declarations name the document’s sections. Where does navigation end, where does the main content start, which part is the footer?
This lesson takes up the elements that answer that question. Their effect on appearance is close to nothing; what they earn is adding a high-level map to the document.
What a Sectioning Element Declares
A reader who can see the screen infers sections from the layout: the strip at the top is the header, the column on the side is navigation, the area in the middle is content. This inference rests on visual cues and is not declared in the document itself.
Semantic sectioning elements turn this inference into a declaration. Once the document says “this is navigation,” that information opens up to non-visual tools too: screen reader users can jump from section to section, reading modes can isolate the main content, indexers can separate navigation links from content links.
The structure that carries this information is called the accessibility tree. It gets derived from the tree in the Document Object Model lesson, and gives every element a role, a name, and a state as a trio. Sectioning elements produce landmark roles in this tree.
Landmark Roles
The correspondences are defined, and a section is conditional on them. The script below applies the rules.
// roles.mjs - what landmark role section elements correspond to const ROLES = { header: "banner", // only at the document's top level nav: "navigation", main: "main", aside: "complementary", footer: "contentinfo", // only at the document's top level form: "form", // only if it has an accessible name section: "region", // only if it has an accessible name article: "article", div: null, }; const doc = [ { tag: "header", depth: 1 }, { tag: "nav", depth: 2, label: "Main navigation" }, { tag: "main", depth: 1 }, { tag: "section", depth: 2, label: "Daily measurements" }, { tag: "section", depth: 2 }, { tag: "aside", depth: 2, label: "Station profile" }, { tag: "div", depth: 2 }, { tag: "footer", depth: 1 }, { tag: "footer", depth: 3 }, ]; for (const item of doc) { let role = ROLES[item.tag]; if ((item.tag === "header" || item.tag === "footer") && item.depth > 1) role = null; if ((item.tag === "section" || item.tag === "form") && !item.label) role = null; const suffix = item.label ? ' ("' + item.label + '")' : ""; console.log((" ".repeat(item.depth - 1) + item.tag + suffix).padEnd(34), role ?? "— not a landmark"); } console.log("--- landmark list ---"); const landmarks = doc .map((item) => { let role = ROLES[item.tag]; if ((item.tag === "header" || item.tag === "footer") && item.depth > 1) role = null; if ((item.tag === "section" || item.tag === "form") && !item.label) role = null; return role ? role + (item.label ? ": " + item.label : "") : null; }) .filter(Boolean); console.log(landmarks.join("\n"));
header banner
nav ("Main navigation") navigation
main main
section ("Daily measurements") region
section — not a landmark
aside ("Station profile") complementary
div — not a landmark
footer contentinfo
footer — not a landmark
--- landmark list ---
banner
navigation: Main navigation
main
region: Daily measurements
complementary: Station profile
contentinfo
The output’s last section is the list a screen reader user sees. It is the document’s map, and the user can jump straight to a section from it.
Three conditions need attention. header and footer elements
produce a landmark only at the document’s top level; a footer
inside an article is not a landmark, it is that article’s footer. A
section element produces a landmark only once it has a name; an
unnamed section does not show up in the list. div never produces a
landmark, under any condition.
The script’s aside correspondence reflects the case where the
element sits in the document’s main flow. For an aside nested inside
an article or a section, the mapping is conditional: counting as a
landmark in that position depends on carrying an accessible name. The
rule is the same one given above for section, and the reason is the
same — an unnamed region does not get added to the list, because it
could not be told apart in it.
The Elements
header is an introductory block: a title, a subtitle, a byline. At
the top level, it is the document’s introduction; inside an article,
it is that article’s introduction.
nav carries navigation links. Not every group of links in a document
has to be nav — the element marks the document’s primary
navigation blocks. Links inside a paragraph are not navigation.
main is the document’s main content, and it occurs once in the
document. It contains no navigation, no footer, no repeated content
spread across the whole site; it holds only content specific to that
document.
aside is content indirectly related to the main flow: a side note, a
profile box, related links. The test is that the main content does not
lose its meaning once the aside gets removed.
footer is a section’s closing information: author, copyright,
related documents. At the top level, it is the document’s footer;
inside an article, it is that article’s footer.
Naming a Section
When more than one landmark of the same kind exists — two navigation blocks, say — which one is which gets told apart by name. There are two paths.
<nav aria-label="Main navigation"> <ul><li><a href="/">Network directory</a></li></ul> </nav> <nav aria-labelledby="station-navigation"> <h2 id="station-navigation">Station sections</h2> <ul><li><a href="#measurements">Measurements</a></li></ul> </nav>
aria-label writes the name directly; it does not appear in the
document. aria-labelledby takes the name from the text of an element
already present in the document, and this is preferred: the name
and the visible heading do not drift apart.
When writing the name, the role’s name does not get repeated. Writing
aria-label="Main navigation menu" gets announced by a screen reader
as “main navigation menu navigation”; the role already comes from the
element.
The Skip Link
A user navigating by keyboard reaches the main content on every page by passing through all of the navigation links. The structure that shortens this is a link written as the document’s first focusable element.
<body> <a href="#main-content" class="skip-link">Skip to main content</a> <header> <nav aria-label="Site-wide navigation"> <ul><li><a href="/stations/">Stations</a></li></ul> </nav> </header> <main id="main-content"> <h1>North Slope Measurement Station</h1> </main> </body>
The link usually gets hidden at the presentation layer and becomes
visible only once it gets focused. The target’s identifier sits on the
main element itself.
When to Use a Meaningless Container
div and span elements declare no meaning. Their reason for
existing is that not every grouping is meaningful: centering a box,
giving a background, building a presentation group needs an element,
and that element has to add no false declaration to the document.
The choice criterion is this: does this group say something about the
document’s structure? If it does, a semantic element gets used; if
not, div gets used. Writing section purely for presentation adds a
meaningless entry to the landmark list — or, being unnamed, adds
nothing at all, and the element stays pointless.
div groups at the block level, span groups within text flow. Both
are handles for the presentation layer.
In the Station Document
<body> <a href="#main-content">Skip to main content</a> <header> <p>Measurement Network</p> <nav aria-label="Site-wide navigation"> <ul> <li><a href="/stations/">Stations</a></li> <li><a href="/method.html">Measurement method</a></li> </ul> </nav> </header> <main id="main-content"> <h1>North Slope Measurement Station</h1> <p>Automatic measurement station built at an elevation of 1840 meters above sea level.</p> <section aria-labelledby="measured-quantities"> <h2 id="measured-quantities">Measured Quantities</h2> <ul> <li>Temperature</li> <li>Relative humidity</li> </ul> </section> <aside aria-labelledby="station-profile"> <h2 id="station-profile">Station Profile</h2> <dl> <dt>Installation elevation</dt><dd>1840 m</dd> <dt>Measurement interval</dt><dd>10 minutes</dd> </dl> </aside> </main> <footer> <p>Measurement Network Working Group</p> </footer> </body>
The document’s landmark list has five entries at this point, and this list is a navigation plane separate from the heading outline built in the previous topic. The two complement each other: landmarks give the document’s coarse sections, headings give the hierarchy inside those sections.
Summary
- Semantic sectioning elements turn section information inferred from the visual layout into a declaration in the document, and produce landmark roles in the accessibility tree.
headerandfooterproduce a landmark only at the document’s top level;sectionproduces one only if it has a name;divnever produces one, under any condition.mainoccurs once in the document and carries only content specific to that document.- More than one landmark of the same kind gets told apart by name; taking the name from a heading visible in the document is preferred, and the role’s name does not get written into the name.
divandspanget used for groupings that declare no meaning; writing a semantic element for presentation purposes adds a false declaration to the document.
Next Step
This lesson used section as a named section and showed article in
the landmark table, but did not open up the distinction between them.
The choice between the two is the most frequently misjudged semantic
decision. The next lesson defines this distinction and gives the test
for whether a section is meaningful on its own.
To keep your progress and take notes, Log in
My notes
Log in to take notes.