The Document Outline Algorithm
<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
<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><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.
<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
<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
<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 |
h1–h6 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.<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 h1–h6 explicitly every time.A Concrete Before/After
<h1> everywhere. Written correctly, headings step down explicitly.mistaken-assumption.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
<!-- Correct: explicit, literal heading levels -->
<h1>API Reference</h1>
<section>
<h2>Authentication</h2>
<section>
<h3>API Keys</h3>
</section>
</section><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
<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.What About <h1> Inside Every <article>?
<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.