Diagram showing nested semantic HTML elements forming a page layout structure

Semantic HTML Layouts

The difference between a layout built with semantic HTML and one built with generic div elements is invisible to most visitors — until something goes wrong. Screen readers lose context, search engines misinterpret content hierarchy, and developers inheriting the codebase spend hours tracing structure that should have been self-documenting from the start. This guide covers the practical application of semantic elements to page layouts — when to use <article>, <section>, <aside>, <nav>, and <main>, how they interact with heading hierarchy, and where the specification's intent diverges from common practice. It is written for theme authors, front-end developers, and anyone shipping production layouts where structure matters as much as appearance.

We have built and maintained layouts for over a decade across WordPress themes, static sites, and component-driven frameworks. The patterns here come from that accumulated experience — not from reading the spec in isolation, but from building real pages, watching real users interact with them, and debugging the failures that result from structural shortcuts.

Why Semantic Structure Matters for Layouts

A semantic layout communicates purpose through markup. When you wrap navigation in <nav>, a sidebar in <aside>, and primary content in <main>, you create a machine-readable map of the page that browsers, assistive technologies, and search crawlers all use to understand what matters and how content relates.

The practical consequence is significant: a well-structured semantic layout survives CSS failures gracefully, remains navigable with assistive technology, and gives search engines high-confidence signals about content hierarchy. A div-soup layout does none of these things, even if it looks identical in a browser with styles loaded.

The W3C HTML specification defines these elements with specific usage intent. Reading the specification directly — rather than relying on summarised blog posts — reveals nuances that most tutorials miss. For example, <section> is not a generic container; it specifically represents a thematic grouping of content, typically with a heading. Using it as a styling hook violates the spec's intent and generates noise for assistive technology users.

Core Elements for Page Layout

<main>

One per page. Contains the dominant content. Excludes repeated elements like headers, footers, and navigation. Every layout we ship uses this as the structural anchor.

<header> and <footer>

These can appear at the page level and within <article> elements. A page-level <header> typically contains the site logo, primary navigation, and possibly a search form. An article-level <header> contains the article title, metadata, and byline. The distinction matters: assistive technology uses these landmarks to navigate between content regions.

<nav>

Reserved for major navigation blocks. Not every group of links is a <nav> — use it for primary site navigation, breadcrumbs, and table-of-contents blocks. Pagination links are a borderline case; we generally include them in <nav> if they are the primary means of navigating a content series.

<article>

Self-contained content that makes sense independently. Blog posts, product cards, comment entries — if you could syndicate it and it would still make sense, it is probably an <article>. Each <article> should have its own heading.

<section>

A thematic grouping within a page. We use <section> when a page has multiple distinct topics that each warrant a heading. The heading requirement is not enforced by browsers, but it is part of the specification's intent.

<aside>

Content tangentially related to the surrounding content. Sidebars, pull quotes, related links blocks. The key test: if you removed the <aside>, would the main content still make complete sense? If yes, it belongs in <aside>.

Heading Hierarchy in Practice

The heading hierarchy (<h1> through <h6>) should follow a strict descending order without skipping levels. One <h1> per page. Subsequent sections use <h2>, sub-sections use <h3>, and so on.

In practice, this means planning your heading structure before writing CSS. We have seen countless layouts where the heading level was chosen based on desired visual size rather than document structure — leading to <h3> elements appearing before any <h2> because the designer wanted smaller text. The fix is straightforward: use CSS to style headings independently of their level, and let the level reflect actual document hierarchy.

Checklist

  • [ ] Page has exactly one <main> element
  • [ ] Page has exactly one <h1> that describes the primary content
  • [ ] Heading levels descend without skipping (no <h1><h3>)
  • [ ] Navigation blocks are wrapped in <nav>
  • [ ] Sidebar content uses <aside> rather than a styled <div>
  • [ ] Each <article> contains its own heading
  • [ ] <section> elements contain a heading that describes the section's theme
  • [ ] Page-level <header> and <footer> are present and contain only appropriate content
  • [ ] The layout remains navigable and comprehensible with CSS disabled

Field-Tested Observations

After building dozens of production layouts with strict semantic structure, several patterns emerge consistently:

The <div> temptation is strongest in component libraries. When you build a button component, a card component, a modal component — each one wants to be a self-contained <div>. The structural cost accumulates: by the time you compose a page from 15 components, you have 15 layers of <div> nesting with no semantic meaning. The discipline of asking "does this component need a semantic element?" at creation time prevents the problem.

Semantic elements create natural refactoring boundaries. When you later need to move a sidebar from the right to the left, or convert a two-column layout to single-column on mobile, the semantic structure tells you exactly what can move and what depends on what. With <div>-soup, these dependencies are invisible.

Testing with a screen reader reveals problems you cannot see. We test every layout with VoiceOver and NVDA before shipping. The experience of navigating a well-structured page versus a poorly-structured one is dramatic — in a well-structured layout, landmark navigation lets you jump directly to the content you want. In a poorly-structured layout, you navigate through every element sequentially.

Common Mistakes

  1. Using <section> as a styling container. If you need a wrapper for visual purposes only, use <div>. Reserve <section> for thematic groupings with headings.

  2. Multiple <main> elements. The specification allows only one <main> per page. If you have tabbed content, the hidden tabs should not be in separate <main> elements.

  3. Putting <nav> around every link group. Footer links, social icons, tags — not every link cluster needs <nav>. Overusing it dilutes the landmark's navigational value.

  4. Skipping heading levels for visual reasons. Use CSS classes to control visual size. Let heading levels reflect document structure.

FAQ

Is it ever acceptable to use <div> in a semantic layout?

Yes. <div> is appropriate for purely presentational wrappers — containers that exist for CSS grid or flexbox alignment without representing a content grouping. The goal is not zero <div> elements; it is using semantic elements where they add meaning.

Should I use <article> for every card in a grid?

If each card represents self-contained content that would make sense independently — yes. Product cards, blog post summaries, and portfolio items are good candidates. UI components like pricing tier boxes are borderline; use your judgment based on whether the content is truly self-contained.

Does heading hierarchy affect SEO?

Search engines use heading hierarchy to understand content structure. A clean hierarchy helps Google determine what a page is about and how subtopics relate to the main topic. Skipped levels or multiple <h1> elements create ambiguity that can dilute topical relevance signals.

What about <figure> and <figcaption>?

Use <figure> for self-contained content referenced from the main flow — images, diagrams, code blocks, quotes. <figcaption> provides the caption. This is particularly valuable for images that need explanatory context beyond an alt attribute.

How do I test semantic structure without assistive technology?

Browser developer tools include accessibility inspectors that show the computed accessibility tree. Chrome's Accessibility tab, Firefox's Accessibility Inspector, and Safari's Accessibility audit all reveal how your semantic elements translate to accessibility landmarks.

Related Reading