Headings done right
h1 through h6 build a table of contents the page never shows. Get the order wrong and the TOC breaks.
A page's headings are not just big bold text. They are the table of contents that screen-reader users browse with one keystroke. They are the structure search engines use to figure out what your page is about. They are the outline a "reader mode" article rebuilds.
Get the headings right, and a blind user can hop to the section they want in two seconds. Get them wrong — by skipping levels, by using <h2> because it "looks the right size", by sprinkling <h1>s everywhere — and that whole experience breaks.
Headings as a TOC
Imagine a screen reader's "headings list" command. The user presses a key, the software pops up a list of every heading on the page indented by level, and the user clicks one to jump there.
h1 Daily Bread Bakery
h2 Sourdough season is back
h3 How the starter works
h3 Where to buy
h2 Visit us
h3 Hours
h3 Address
That's the page. No prose, no images, no nav — just the heading skeleton. If the skeleton tells a coherent story, your page is well-structured. If it looks like a jumble, your page is too.
This is also roughly what search engines see. They cannot read your CSS, but they read your headings.
Why level order matters
Heading levels are not font sizes. They are depth in the outline. <h1> is the page topic. <h2> is a major section of that topic. <h3> is a subsection of that section. And so on, down to <h6>.
A useful picture: headings are like the bullets in a nested list. h1 is the top bullet. h2s are sub-bullets under it. h3s are sub-sub-bullets under the most recent h2. The browser does not care about the indentation visually, but the meaning is the same — depth.
The picture above is the same as the screen-reader headings list. Indentation = depth = heading number.
<article> <h2>Sourdough season is back</h2> <p>Our wild-yeast loaf returns next Friday...</p> <h3>How the starter works</h3> <p>We feed it twice a day...</p> <h3>Where to buy</h3> <p>The Saturday market on Bridge Street...</p> </article>
The article has one major topic (h2) with two sub-topics (h3s). That is the whole structure. A reader navigating by headings sees three entries: the section title and its two sub-headings. They can jump straight to "Where to buy" without reading the rest.
How many h1s?
The traditional rule was "one <h1> per page". The rule was easy to follow and made sense when every page was hand-built.
Modern web pages built from components blur this. A blog post page often has the post title as the page-level <h1>, and individual cards on a "related posts" sidebar may also each have their own heading. With nested <article>s, each article can technically have its own <h1> and the outline still works — heading levels reset inside an article.
In practice, the safe advice is still: use one <h1> per page, and make it the page's topic. Inside <article> elements, a second <h1> is permitted by the spec but understood by fewer tools. If you are building a typical content page, one <h1> is the right call.
The page's <title> (in the head, used for the browser tab) and the page's <h1> (in the body, the visible title) are usually similar but not identical. The title might say "Sourdough season — Daily Bread Bakery"; the h1 might say "Sourdough season is back". Both are fine; both serve different audiences.
Don't skip levels
The rule that catches people: do not skip from <h2> to <h4> in the same outline. Going down by more than one level confuses screen-reader users (they expect to navigate by hierarchy) and breaks the implicit table of contents.
<!-- broken: jumps from h2 to h4, no h3 between --> <h1>Pricing</h1> <h2>Plans</h2> <h4>Free tier</h4> <h4>Pro tier</h4>
A screen reader will still announce the headings, but the outline is missing a rung. Was there meant to be an <h3> "Tiers" between them? The user can't tell.
<h1>Pricing</h1> <h2>Plans</h2> <h3>Free tier</h3> <h3>Pro tier</h3>
The fix is rarely complicated: pick the next level down. Going back up (from <h3> to <h2>) to start a new sibling section is fine — that is exactly what the outline is for. Only the down-skip is the bug.
h1, h2, h3, h2, h4, h3, h2. Where is the bug?Style is a separate concern
The biggest reason people pick the wrong heading level is that they are picking by appearance. "I want medium-sized text, so I'll use <h3>." That logic produces broken outlines.
The right move: pick the level by depth, then style it however you want.
/* The h2 that opens an article gets the "hero" look. */
article > h2:first-child {
font-size: 2.5rem;
font-weight: 600;
}
/* But it stays an h2 — its level is the page-outline's level,
independent of how big it looks. */In CSS, font-size can be anything. In HTML, the heading level has to match the structure. They are independent dials.
If you ever feel the urge to write <h2 style="font-size: small">, take that as a sign you have picked the wrong level. The level is for the outline; the size is for the design.
Tools like Lighthouse, axe, and most browser DevTools include an "outline" or "headings" check. Run it on your page and read the result aloud. If the read-out does not match the page, your headings are wrong.