HTML5 Semantic Elements: A Diagnostic Guide for <main>, <nav>, and <article>
A diagnostic guide for fixing broken HTML5 semantic structure involving <main>, <nav>, and <article>. Identify nesting errors, missing labels, and accessibility tree issues.
24 Dec 2025, 09:02 UTC

The Symptom: Flat Landmarks and Invisible Content
When a page uses HTML5 semantic elements but screen readers announce a flat sequence of generic containers, or SEO crawlers cannot isolate the primary content, the markup is often syntactically valid but semantically misplaced. The useful takeaway is that adding more tags rarely fixes the problem; correcting where <main>, <nav>, and <article> sit in the document tree—and how they are labeled—restores the landmarks that assistive technology and search engines rely on.
Two terms matter here. A landmark role is the accessibility-tree equivalent of a page region (for example, main, navigation, or article). The document outline is the heading and section hierarchy that browsers and crawlers derive from semantic elements. When nesting is wrong, both break.
Cause and Diagnostic Table
| Recognizable Condition | Likely Cause | Diagnostic Signal |
|---|---|---|
Screen reader announces main while inside an article context |
<main> nested inside <article>, <aside>, <header>, <footer>, or <nav> |
Accessibility tree shows a main landmark as a child of another landmark |
| Two or more navigation regions announced identically | Multiple <nav> elements without aria-label or aria-labelledby |
Accessibility tree lists repeated navigation landmarks with no distinguishing name |
| Primary content not exposed as a distinct region | Layout built entirely from <div> elements; no <main> or <article> present |
Accessibility tree lacks main or article landmarks |
| Section announced as a generic region | <section> used as a styling wrapper without an h1–h6 heading |
Accessibility tree shows region with no accessible name |
| Footer content announced inside header context | <footer> placed inside <header> or outside <body> |
Validator reports element not allowed in current context; accessibility tree shows misplaced contentinfo |
Ordered Checks
-
Validate the document tree. Run the page through the W3C Markup Validation Service at
https://validator.w3.org/or a local validator instance. No special permissions are required for the web service; for a local run, use a placeholder such asyour-page.html. Expected check: zero errors related to element nesting or context. Risk: the validator catches syntax and some nesting rules, but it does not measure whether landmarks are useful to users. -
Inspect the accessibility tree. Open Chrome or Edge DevTools (
Elements>Accessibility) or the Firefox Accessibility panel. Expected check: exactly one top-levelmainlandmark;articleandsectionlandmarks appear only where intended;navigationlandmarks carry accessible names. -
Audit navigation labels. Run the following in the browser DevTools console on the affected page:
// Run in the page console after loading the affected document document.querySelectorAll('nav').forEach((nav, index) => { const label = nav.getAttribute('aria-label'); const labelledBy = nav.getAttribute('aria-labelledby'); const hasLabel = label || (labelledBy && document.getElementById(labelledBy)); console.log(`nav[${index}]: ${hasLabel ? 'labeled' : 'MISSING LABEL'}`); });Expected check: every
navlogslabeled. Risk: console code executes in the page origin; only run it on trusted pages. -
Verify headings inside sections. Review the source or use the Elements panel. Expected check: each
<section>contains at least one<h1>–<h6>as a direct or indirect child; otherwise it should be a<div>.
Fixes Tied to Diagnostic Findings
Relocate <main> to the document root level
Finding: <main> nested inside sectioning content.
Action: Move <main> so it is a direct child of <body> or the top-level layout container. Remove any <main> inside <article>, <section>, <aside>, <nav>, <header>, or <footer>.
Risk: CSS selectors such as body > div.wrapper > main or descendant selectors may break. Update selectors to target the new path.
Distinguish multiple navigation landmarks
Finding: Repeated unlabeled <nav> elements.
Action: Add aria-label="Primary", aria-label="Footer", or use aria-labelledby pointing to a visible heading ID. Do not add ARIA roles such as role="navigation" because the native element already exposes that role.
Risk: Redundant ARIA attributes can create conflicting metadata if misapplied.
Replace structural <div> wrappers with semantic containers
Finding: No <main> or <article> in the accessibility tree.
Action: Identify the primary content wrapper and change <div class="content"> to <main> or <article>. Use <article> for self-contained compositions (blog posts, product cards) and <main> for the dominant content of the document.
Risk: Existing CSS rules targeting div.content will no longer match. Update selectors to main.content or add the semantic tag to the selector list.
Add headings to sections or revert to <div>
Finding: <section> without a heading.
Action: If the region represents a thematic grouping, insert an <h2> or appropriate level. If it is only a styling hook, replace <section> with <div>.
Risk: Changing heading levels alters the document outline and may affect how search engines generate snippets.
Correct <footer> placement
Finding: <footer> inside <header> or outside <body>.
Action: Move the <footer> to be a direct child of <body> for site-wide footers, or scope it inside the relevant <article> or <section> for content-specific footers. Never place it inside <header>.
Risk: Global footer styles may need scoping to avoid applying to article-level footers.
Escalation Criteria
- If the project must support Internet Explorer 8 or earlier, escalate to add an HTML5 shiv (for example, the
html5shivscript) and ensure CSS selectors do not rely solely on semantic tags for layout in those browsers. - If changing structural tags breaks a large CSS codebase, escalate to a design-system owner or frontend lead for a coordinated selector refactor.
- If automated accessibility scans report landmark conflicts after fixes, escalate to an accessibility specialist to audit ARIA usage.
- If the W3C validator reports errors that element relocation does not resolve, escalate to a senior frontend engineer or the framework maintainer.
Limitations and Practical Verification
Modern evergreen browsers (Chrome, Firefox, Safari, Edge) expose semantic landmarks in the accessibility tree, but Internet Explorer 8 and earlier require a CSS shim to recognize the tags. The W3C validator identifies nesting violations but does not measure whether landmarks are useful. Browser accessibility trees vary slightly across engines, so test in at least two browsers.
To verify the result:
- Re-run the W3C validator on the updated file and confirm no new errors.
- Reload the page and open the Accessibility panel. Confirm a single top-level
mainlandmark, namednavigationlandmarks, andarticleorsectionregions with accessible names. - Use a screen reader (NVDA on Windows or VoiceOver on macOS) to jump between landmarks. Verify that each region is announced with its intended name and that the main content is reachable without traversing generic containers.
- Inspect the rendered DOM to confirm the primary content is no longer obscured by generic wrappers.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.