Search code examples
htmlaccessibilitysemantic-markup

Accessibility: Main page navigation contains h2, h1 heading is below


Consider this markup:

<!doctype html>
<html>

    <head>
    </head>

    <body>
        <header>
            <nav>
                <ul>
                    <li>
                        <a href="/">
                            <h2>Home</h2>
                        </a>
                    </li>
                    <li>
                        <a href="/other">
                            <h2>Other</h2>
                        </a>
                    </li>
                </ul>
            </nav>
        </header>
        <main>
            <h1>Page Title</h1>
        </main>
    </body>

</html>

This markup is "fine" but, if I understood correctly, neither accessible nor semantically correct/recommended. The issue is with the h2 appearing before h1, which creates a confusing document outline:

1. Untitled BODY
  1. Home
  2. Other
2. Page Title

However the obvious intended outline is:

1. Page Title
  1. Home
  2. Other

The naive way to achieve this would be to just "move" the whole nav somewhere after the h1, either inside main or after it. But this is not how I want my page to look like, I obviously want my navigation above my main page content. Of course I could use CSS to somehow move the nav visually up, but that doesn't seem correct either.

My question is: What is the most common, but accessible solution to this "dilemma"? Note that I definitely want the nav to keep using h2 (or any other heading level), as that is, as far as I know, the recommended "semantic" way. This way, the navigation links will also show up in the document outline. Is there some way to just tell a screen reader or browser that some headings should "swap" position in the document outline, maybe through some aria- attributes? Is there some alternative I'm missing?

One solution I thought of, but "feels" wrong to me:

<!doctype html>
<html>

    <head>
    </head>

    <body>
        <header>
            <h1>
                Page Title
            </h1>
            <nav>
                <h2>
                    Page Navigation
                </h2>
                <ul>
                    <li>
                        <a href="/">
                            <h3>Home</h3>
                        </a>
                    </li>
                    <li>
                        <a href="/other">
                            <h3>Other</h3>
                        </a>
                    </li>
                </ul>
            </nav>
        </header>
        <main>
            <h2>Main Content Title</h2>
        </main>
    </body>

</html>

This feels a bit verbose but at least results in a correct document outline. Is this really the only way to solve my problem?


Solution

  • The proper way to mark up this kind of content (in terms of semantics and accessibility) is as follows—

    <header>
      <nav aria-label="Main Navigation">
        <ul>
          <li><a href="#">Home</a></li>
          <li><a href="#">About</a></li>
          <li><a href="#">Lorem</a></li>
          <li><a href="#">Ipsum</a></li>
        </ul>
      </nav>
    </header>
    <main>
      <h1>Page Title</h1>
      <p>Additional page content...</p>
    </main>
    

    Navigation items should not be marked up as headings. A list of links is all that is necessary. See this example from the Mozilla documentation on the navigation element.

    If you want to add a hidden label for the navigation for assistive technologies, you can add an aria-label attribute to the <nav> element, as detailed in this example from the W3C Accessibility Guidelines Working Group. Additionally, this approach avoids needing to add a heading out of order.

    Finally, be sure to include the document title (<h1>) within the <main> element, as in this example from the Mozilla documentation on the main element.