HTMLDocument Outline & Landmarks

The Document Outline Algorithm

Early in the HTML5 spec, there was an idea called the outline algorithm: sectioning elements like <section> and <article> would each reset heading levels, so an <h1> nested three <section>s deep would be treated as equivalent to an <h4> in the page's "true" outline. It's a nice idea in theory. In practice, no browser or screen reader ever fully implemented it, and it has since been removed from the HTML specification.
What the Algorithm Proposed

proposed-outline.html

HTML
<article>
  <h1>Guide to Coffee Brewing</h1>

  <section>
    <h1>Choosing Beans</h1>
    <!-- Under the (never-implemented) algorithm, this h1
         would be treated as a level-2 heading, because it's
         nested inside <article> > <section>. -->
  </section>
</article>
The intent was that authors could reuse <h1> everywhere—inside every nested section—and let the DOM structure determine the effective heading level automatically.
Why It Doesn't Work in Practice
  • No major browser ever implemented the outline algorithm for its accessibility tree.

  • Screen readers build their heading navigation from the literal h1-h6 level, not from sectioning depth.

  • The HTML Living Standard has formally removed the concept of the outline algorithm.

  • Relying on it means real assistive technology users get a heading structure that doesn’t match what the algorithm intended.

An h1 nested inside a section is still announced as an h1
Regardless of how deeply a heading is nested inside <section>/<article>/<aside>, screen readers and browsers treat it strictly by its literal tag name. Nesting alone changes nothing about how it's announced.
Current Best Practice
Since the outline algorithm was never real in practice, write headings the traditional way: one <h1> per page, and strictly sequential nesting after that—don't skip from <h2> straight to <h4>, even inside deeply nested sections.

best-practice.html

HTML
<body>
  <h1>Guide to Coffee Brewing</h1>

  <section>
    <h2>Choosing Beans</h2>
    <p>...</p>

    <section>
      <h3>Roast Level</h3>
      <p>...</p>
    </section>

    <section>
      <h3>Grind Size</h3>
      <p>...</p>
    </section>
  </section>

  <section>
    <h2>Brewing Methods</h2>
    <p>...</p>
  </section>
</body>

Rule

Why

Exactly one <h1> per page

Establishes a single, unambiguous top-level topic for the page

Never skip levels going deeper (h2 → h4)

Screen reader users navigating "by heading level" expect a logical, unbroken hierarchy

Sectioning elements don’t change heading levels

Nesting a heading inside <section>/<article> has no automatic effect on its announced level

Test with a headings-only view
Most screen readers and several browser extensions offer a "headings list" view that shows just your h1h6 structure. If it doesn't read like a sensible table of contents on its own, your heading levels need fixing—regardless of how the sectioning elements are nested.
Sectioning elements are still worth using
Dropping the outline algorithm doesn't mean <section>/<article> are useless—they still provide real landmark and grouping semantics. Just don't rely on them to auto-adjust your heading levels; choose the correct h1h6 explicitly every time.
A Concrete Before/After
Imagine a documentation page with a top-level title, three major topics, and sub-topics under one of them. Written under the mistaken assumption that the outline algorithm works, an author might reuse <h1> everywhere. Written correctly, headings step down explicitly.

mistaken-assumption.html

HTML
<!-- Mistaken: relies on the never-implemented outline algorithm -->
<h1>API Reference</h1>
<section>
  <h1>Authentication</h1>
  <section>
    <h1>API Keys</h1>
  </section>
</section>

correct-headings.html

HTML
<!-- Correct: explicit, literal heading levels -->
<h1>API Reference</h1>
<section>
  <h2>Authentication</h2>
  <section>
    <h3>API Keys</h3>
  </section>
</section>
A screen reader's heading list from the first example reads as five identical top-level <h1>s—flat and confusing. The second example reads as a proper nested outline: exactly what a table of contents should look like.
Automated Checks Can Help
Accessibility linting tools (browser extensions, CI-integrated checkers) commonly flag two specific problems: more than one <h1> on a page, and heading levels that skip (e.g. an <h2> followed directly by an <h4> with no <h3> in between). Running one of these checks against a page is a fast way to catch heading-structure mistakes before they reach production.
Visual heading size is not the same as heading level
Don't choose a heading tag based on how large you want the text to look—that's a CSS decision. Choose the tag based on the content's actual position in the logical outline, then style it with CSS however you like.
What About <h1> Inside Every <article>?
A related myth is that each <article> on a page (say, in a blog listing) should use its own <h1>, based on the same abandoned outline theory. In practice, keep a single page-level <h1> and give each article a lower-level heading (<h2> is typical) that fits its actual position in the page's real, literal heading hierarchy.
  • The HTML5 "outline algorithm" (headings implicitly re-leveled by sectioning depth) was never implemented by browsers or screen readers.

  • It has been formally removed from the current HTML Living Standard.

  • Heading levels are always taken literally, regardless of how deeply nested the heading is.

  • Best practice: one <h1> per page, and strictly sequential h2/h3/h4 nesting written explicitly.