What semantic hierarchy actually is
A web page is a document. Like any document, it has a structure: a title, sections, sub-sections, navigation, the main content, and the bits around the edges. Semantic hierarchy is just the act of writing that structure into the HTML, so anything that reads the page can tell what is what.
Three pieces matter:
- Headings:
h1throughh6. They define the outline of the document, like chapter titles in a book. - Landmarks:
header,main,nav,article,aside,footer. They mark the regions of the page. - Content elements:
buttonfor buttons,ulandlifor lists,afor links,pfor paragraphs. The right tag for the right thing.
If you do this well, the same markup works for everyone: a sighted user reading the styled page, a search crawler parsing the structure, and a screen reader announcing the page to a blind user. The same logic that makes alt text on images serve both audiences applies here. One source of truth.
Why it matters
Two audiences read your HTML directly: search engines and assistive technology. Neither sees your design. Both rely on the tags.
Google parses the structure to understand what the page is about. The h1 tells it the topic. The h2 headings tell it the main sections. Lists, articles, and main regions help it decide which part is the actual content versus the navigation or the footer.
A screen reader does the same thing for a different reason. Users who cannot see the screen press a key to jump from heading to heading, or to skip straight to the main landmark. If your page has six h1 tags, no main, and buttons that are actually div elements, that user is stuck scrolling through every word in linear order.
Same markup, both audiences served. That is the point.
The h1 rule
One h1 per page, and it should describe the page topic.
That sounds obvious. Most CMSes get it wrong. They put the site logo in an h1 on every page, so every page has the same h1: the company name. Then the actual page title becomes an h2 or, worse, a div styled to look big.
Fix it:
- The logo in the site header should be a regular link, often inside a
<header>landmark. - The page topic, the thing that is unique to this page, should be the
h1. - On a blog post, the post title is the
h1. On a product page, the product name is theh1. On the home page, the main proposition is theh1.
Open any page on your site, hit View Source, search for <h1. You should find one tag, and the text inside should match what the page is about.
Heading order
Headings are an outline. Outlines do not skip levels.
The rule is simple: an h2 follows an h1, an h3 follows an h2, an h4 follows an h3. You can go back up (an h2 after an h3 starts a new section) but you do not jump down. An h1 followed by an h4 confuses every parser.
A common mistake: someone wants a small heading visually, so they grab an h4 because it looks the right size. Stop doing that. Use the right level for the structure, then use CSS to make it look however you want. A h2 styled to 14px is fine. A h4 used as a font-size shortcut is broken structure pretending to be styling.
Landmarks
Landmarks are the regions of the page. The main ones:
<header>: the top of the page or the top of an article.<nav>: a block of navigation links. Most pages have one in the header and sometimes another in the footer.<main>: the main content of the page. One per page. This is the region screen reader users jump to with a single key.<article>: a self-contained piece of content. A blog post, a comment, a product card.<aside>: tangential content. A sidebar, a related-posts widget, a callout.<footer>: the bottom of the page or the bottom of an article.
You do not need every landmark. You do need <main>, and you should not have two of them. Wrap your real content in it. That single change makes your page navigable for assistive tech in a way that no amount of ARIA can match.
Content elements
A button is a <button>. A link is an <a> with an href. A list is a <ul> or <ol> with <li> children.
This sounds trivial. It is not, because frameworks and design systems push people toward <div> for everything. Three patterns to fix:
- Divs that should be buttons. If clicking it does something on the current page, it is a button. A
<div onClick>does not get keyboard focus, does not announce itself as a button to screen readers, and does not respond to Enter or Space. Use<button type="button">and style it however you want. - Lists made of styled paragraphs. A row of items is a list. Wrap them in
<ul>and let each item be a<li>. Screen readers announce βlist of 5 itemsβ and let users skip the whole thing if they want. - Links that should be buttons, or buttons that should be links. If it navigates to a URL, it is a link. If it triggers an action on the current page, it is a button. Do not use one for the other.
Common mistakes, in one place
A short list of things to grep for in your codebase:
- More than one
<h1>per page. - An
<h1>that says the same thing on every page (usually your site name). - Headings used out of order:
h1,h3,h2,h5. - A heading level chosen for its default font size rather than its structural meaning.
- Missing
<main>, or two<main>regions. <div>elements with click handlers and no keyboard support.- Lists rendered as a stack of
<p>tags with bullet characters typed in by hand. - Generic
<span>everywhere, with the actual structure smuggled into class names.
Each one is small. Together they make a page that looks fine and parses badly.
A quick audit you can do in five minutes
Open the page in Chrome or Firefox. Open DevTools. Find the Accessibility panel (in Chrome it lives under Elements, then Accessibility tree on the right side).
Look at the tree. You should see your landmarks at the top level: header, main, footer. Inside main you should see your headings in order, with the topic h1 first.
If the tree looks like a flat list of generic regions, your page is missing structure. Fix the landmarks first, then the headings.
A second option: install a free outline extension like HeadingsMap. It draws your heading tree in a side panel, the same way a table of contents would. Pages with broken hierarchy show up immediately.
A third option, no install: open the page, view the source, and read the headings out loud as if you were narrating the page to someone on the phone. If the result makes sense as a spoken outline, the structure is fine. If it does not, you know where to fix.
The practical takeaway
Write the structure as you would explain the page to someone who cannot see it.
Start with: βThis is a page about X.β That is your h1. Then: βIt has these sections.β Those are your h2 headings. Inside each section, sub-points become h3. Around the main content, navigation goes in <nav>, the central content goes in <main>, the page identity goes in <header> and <footer>.
Once that outline reads cleanly out loud, style it visually with CSS. Make the h2 small if you want. Hide a heading with a screen-reader-only utility if it is decorative. The structure stays correct, and the design lives where it belongs.
If you are interested in the related performance side of SEO, the Core Web Vitals piece covers it. If you are working on imagery, see WebP versus PNG and JPG. For multilingual structure, hreflang and canonical is the next read.
If you use the SEO Expert app, its outline view shows the heading tree of any page. Same idea as the accessibility tree in DevTools, just framed for SEO work.
Frequently asked questions
How many h1 tags should a page have?
One. The h1 should describe the topic of the page, not the site as a whole.
Can I skip heading levels for visual design? No. Use the correct level for structure, then use CSS to set the size and weight you want.
Does Google still care about heading hierarchy? Yes. Google has said it parses headings to understand page structure. It tolerates imperfect markup but rewards clean structure.
What is the difference between a section and an article?
An <article> is self-contained: it would still make sense if you copied it elsewhere. A <section> is a thematic grouping inside a larger document. When in doubt, use <section>.
Do I need ARIA roles if I use the right HTML tags? Usually no. Native HTML elements come with the right roles built in. ARIA is for filling gaps when you cannot use the right element, not for replacing it.