Fixing Non-Semantic HTML Structure
Many pages are built almost entirely from div and span elements with class names that mean something to the designer and nothing to a machine. A browser displays them perfectly, so nobody notices.
An AI crawler reading the HTML has to guess where the menu ends, where the article starts, which text is a sidebar advert and which is the answer. Semantic elements such as main, article, nav and properly ordered headings remove the guesswork. This guide shows how to find the gaps in your templates and replace the key wrappers, usually without changing how the page looks.
Semantic elements in HTML such as main, article and nav tell crawlers what each part of the page is.
What semantic HTML tells a machine
HTML elements carry meaning as well as shape. A <div> means "a box" and nothing
more. A <nav> means "this is navigation", <main> means "this is
the reason the page exists", and <h2> means "a new topic starts here, one level below
the page title". Class names such as content-wrap or sidebar-left look meaningful
to people, but they are not part of any standard, so a program cannot rely on them.
When an AI crawler turns a page into text, the first job is to separate the main content from everything around it: header, menus, cookie notice, related links, newsletter box, footer. Extraction tools use a mix of signals to do this, and semantic elements are among the clearest. With them, the job is close to mechanical. Without them, the tool falls back on guesses based on text density and link counts, and it sometimes guesses wrong, dropping a short answer or keeping a block of menu links as if it were content.
The same structure serves people using assistive technology. Screen readers list landmarks and headings so users can jump straight to the main content. That is why most of the fixes here also appear in accessibility guidance, and why getting them right has benefits beyond AI crawlers.
<div class="site-nav"> for <nav class="site-nav">
keeps every style that uses the class.The elements that matter most
| Element | Use it for | Rules of thumb |
|---|---|---|
<main> | The primary content of the page | One visible per page. Not inside header, footer, nav or aside. |
<article> | A self-contained piece: blog post, product, news item, review, comment | Should still make sense if lifted out of the page. Can be nested, such as comments inside a post. |
<section> | A thematic part of a larger piece, with its own heading | If it has no natural heading, it probably should be a div. |
<nav> | Major blocks of navigation links | Main menu, breadcrumb, table of contents, pagination. Not every group of links. |
<aside> | Content related to, but separate from, what is around it | Sidebars, pull quotes, related reading. Tells extractors this is secondary. |
<header> and <footer> | Introductory and closing content for the page or for an article | An article can have its own header holding the title and byline. |
<h1> to <h6> | Headings that describe the section that follows | Chosen for level in the outline, never for font size. |
<time> | Dates and times | Put a machine-readable value in the datetime attribute. |
<figure> and <figcaption> | An image, chart or code sample with a caption | Links the caption to the thing it describes. |
<table>, <ul>, <ol>, <dl> | Tabular data, lists and term-definition pairs | Real tables keep rows and columns connected when the page is turned into text. |
Before and after: one page template
Here is a typical service page from a fictional firm, Brookfield Heating, built the way many page builders and older themes produce it:
<div class="wrapper">
<div class="top-bar"><div class="logo">...</div>
<div class="menu"><div class="menu-item" data-url="/boilers">Boilers</div>...</div>
</div>
<div class="content">
<div class="big-title">Boiler servicing in Leeds</div>
<div class="posted">Updated 3 Sept 2026</div>
<div class="text">...</div>
<div class="subtitle">What a service includes</div>
<div class="bullet">Flue check</div><div class="bullet">Gas pressure test</div>
</div>
<div class="side">Latest offers...</div>
<div class="bottom">...</div>
</div>
And the same page with semantic elements. The classes can stay, so the design does not move:
<header class="top-bar">
<a class="logo" href="/">Brookfield Heating</a>
<nav class="menu" aria-label="Main">
<ul><li><a href="/boilers/">Boilers</a></li>...</ul>
</nav>
</header>
<main class="content">
<article>
<header>
<h1>Boiler servicing in Leeds</h1>
<p>Updated <time datetime="2026-09-03">3 September 2026</time></p>
</header>
<p>...</p>
<section>
<h2>What a service includes</h2>
<ul><li>Flue check</li><li>Gas pressure test</li></ul>
</section>
</article>
<aside class="side" aria-label="Offers">Latest offers...</aside>
</main>
<footer class="bottom">...</footer>
Notice what changed beyond the wrappers. The menu items became real links, so a crawler can follow
them. The "big title" became the one <h1> and the subtitle became an <h2>.
The bullet divs became a list. The date gained a machine-readable value. None of this needs new design
work, but each change removes a guess the crawler would otherwise have to make.
How to find the problems
- Run the audit. The Agent Readiness Audit reviews the semantic HTML of the page it fetches, so start with one URL per template and note what it reports.
- Look at the landmarks. In Chrome or Edge developer tools, the Accessibility pane
shows the accessibility tree, where
main,navigation,banner,contentinfoandcomplementaryappear as roles. Firefox has a similar Accessibility Inspector. If you see nomain, or several, that is the first fix. - Print the heading outline. Paste this into the developer tools console to list every heading in order:
Look for a missing or duplicated h1, skipped levels, headings used for things like "Share this" or prices, and real section titles that are not headings at all.document.querySelectorAll('h1,h2,h3,h4,h5,h6').forEach(h => console.log(h.tagName, h.textContent.trim().slice(0, 70))); - Try reader mode. Firefox Reader View tries to extract the main article. If it shows the menu, drops the opening paragraph or refuses to open, extractors are likely to struggle too.
- Validate. The W3C Nu HTML Checker flags broken nesting, such as a list item outside a list, which can confuse parsers as much as missing semantics.
The fix, step by step
Step 1
Map the page into regions
Take a screenshot of one page from each template and draw boxes on it: site header, main menu, breadcrumb, the main content, sidebar, related links, newsletter or offer blocks, and footer. Then open the template source and find the element that wraps each box. This map tells you which divs need to become which elements, and it stops you wrapping the sidebar inside the main content by mistake.
Step 2
Swap the outer wrappers for landmarks
In
the shared layout template, change the site header wrapper to <header>, the main menu
to <nav>, the footer wrapper to <footer> and the content area to
a single <main>. Keep existing classes and IDs so styles and scripts still work. Where
there is more than one nav, give each an aria-label such as Main or Breadcrumb. Check that
header, nav and footer sit outside main.
Step 3
Mark the main piece of content as an article
Inside main, wrap the post, product or service description in <article>,
with its own header holding the h1, the byline and the date. Move secondary blocks such as related posts,
offers and author promotions out of the article and into <aside>. On listing pages,
wrap each card in its own article instead. Use <section> only for parts that have
a proper heading of their own.
Step 4
Rebuild the heading outline
Give each page one h1 that states what the page is about, usually matching the title. Turn each real section title into an h2, and subsections into h3, without skipping levels. Where a heading tag is only there for its size, such as a price, a phone number or a widget title, change it to a paragraph or span and keep the look with a class. Headings should read like a table of contents for the page.
Step 5
Use real lists, tables and links
Replace
runs of divs styled as bullets with <ul> or <ol>, and grids of
divs showing specifications or prices with a <table> that has header cells. Use <dl>
for label and value pairs. Anything that navigates must be an <a href> with a real
URL, not a div with a click handler or a data attribute read by script, and anything that performs an
action should be a <button>.
Step 6
Add time, figure and address where they fit
Wrap published and updated dates in <time> with an ISO date in the
datetime attribute, so the date cannot be misread. Put charts, diagrams and product photos that have
captions inside <figure> with a <figcaption>. Use <address>
for the contact details of the business or author that the page belongs to, rather than for any postal
address mentioned in passing in the text.
Step 7
Validate and test extraction
Run the changed pages through the W3C Nu HTML Checker and fix nesting errors, such as a main inside a header or list items outside a list. Print the heading outline again, check landmarks in the accessibility tree and open the page in reader mode to confirm it now picks out the right content. Check the design has not shifted, then run the Agent Readiness Audit again on each template.
Platform notes
WordPress
Most current themes already use header, main and footer; the gaps are usually inside the content.
In the block editor, the Group block has an HTML element setting under Advanced that lets you output
it as main, section, article, aside, header or footer instead of a div. Elementor containers have a similar
HTML tag option. Classic themes may need edits to header.php, footer.php and
the single post template, ideally in a child theme so updates do not overwrite them. More in the WordPress
agent readiness guide.
Shopify
Shopify's recent free themes wrap page content in a main element inside layout/theme.liquid.
The common problem is section files where product titles, collection headings and app blocks use the
wrong heading level, or where headings are chosen for size in the theme editor. Check each section file's
heading tags. See the Shopify
agent readiness guide.
React and other component frameworks
Components tend to add a wrapper div each, which is how deep div nesting builds up. Use fragments where a wrapper has no purpose, let layout components render header, nav, main and footer, and pass the heading level into reusable card components rather than hard-coding an h3 everywhere. The React and Next.js guide covers rendering alongside this.
Common mistakes when converting
- Section everywhere. Replacing every div with a section adds noise, not meaning. A section should be a part you could list in a table of contents.
- Two main elements. Often caused by a theme wrapping the page in main and a page builder adding another. Only one should be visible.
- ARIA as a substitute. Adding
role="main"to a div works for screen readers, but the native element is simpler and is what the specification recommends. Use ARIA roles only where no element fits. Adding a role to an element that already has it, such as<nav role="navigation">, is harmless but unnecessary. - Visual order that differs from source order. CSS can place the sidebar first on screen while it comes last in the HTML, or the reverse. Crawlers read source order, so the main content should come early in the source.
- Hidden headings for keywords. Headings hidden from view to add keywords can be treated as spam and add nothing a crawler trusts.
- Tables for layout. The opposite mistake. Use tables for data with rows and columns, not to position page regions.
Semantic structure is one part of making content easy to extract. Facts locked in images, text only revealed by script-loaded tabs, and content in PDFs are separate problems, handled in fixing poor content extractability. Heading order in more depth is covered in the heading hierarchy guide.
1. Do AI crawlers really care about semantic HTML?
AI providers do not publish the details of how they extract text, so nobody outside those companies can say exactly how much weight each element carries. What is well established is that content extraction tools, including open-source ones widely used to prepare web text, look for signals that separate main content from page furniture, and semantic elements are among the clearest. Clean structure lowers the chance of your answer being cut off or mixed with menu text.
2. Will switching to semantic elements change how my site looks?
Usually not. Browsers give header, main, nav, article, section, aside and footer the same default display as a div, so a straight swap that keeps the class names looks identical. Changes show up where your stylesheet targets element names, such as a rule for every section or every nav, or where a heading changes level and the h2 styles differ from the h3 styles. Compare a few pages side by side after the change to catch these.
3. Is it wrong to have more than one h1 on a page?
HTML does not forbid it, and Google has said multiple h1 elements are not a problem for its systems. The practical case for one h1 is clarity: a single top-level heading that states what the page is about gives every reader, human or machine, an unambiguous title. Many templates end up with two h1s by accident, such as a logo marked up as h1 on every page, and fixing that tidies the outline without any downside.
4. What is the difference between article and section?
An article is a complete, self-contained piece that would still make sense on its own, such as a blog post, a product, a review or a comment. A section is a part of something larger, grouped around one theme and normally introduced by its own heading, such as the Specifications part of a product page. A useful test is to imagine the block on its own in a feed reader; if it stands alone, use article.
5. Does semantic HTML help my Google rankings?
Google has not said that using particular HTML elements is a ranking factor, and it is good at understanding messy pages. The benefits are indirect: clearer headings help it understand what each part of a page covers, real links can be followed, and proper tables and lists are easier to use for featured snippets. Semantic markup is also central to accessibility, which matters for visitors and, in many cases, for legal duties around equal access to services.
6. My page builder only outputs divs. What can I do?
Check the settings first, because most current builders let you choose the HTML tag for containers and headings, often under an advanced tab. Set the outer wrapper of the content to main or article, the menu container to nav and section titles to real heading levels. Where the builder genuinely cannot do it, the theme around it can still supply header, nav, main and footer, which covers the most important landmarks even if the inner content stays plain.
7. Should I also add schema markup if the HTML is semantic?
They do different jobs, so doing both is worthwhile. Semantic HTML describes the shape of the page: where the main content is and how it is divided. Structured data in JSON-LD describes facts about the thing the page is about, such as the author, the organisation, a product price or an event date. Neither replaces the other. The JSON-LD coverage guide explains which schema types suit which page templates and how to connect them together.
The Agent Readiness Audit reviews the semantic HTML of your page, measures how easily the content can be extracted and tests how much depends on JavaScript, alongside crawler access, llms.txt and JSON-LD checks.
Open Agent Readiness Fixes โ