The Case for Meaning Over Appearance

Every HTML element you write is a decision about what a piece of content is — not just what it looks like. That distinction, easy to overlook when you’re shipping features and meeting deadlines, is precisely where interfaces start to diverge: those that work for everyone versus those that work only for a narrow slice of users navigating under ideal conditions.

Semantic HTML is the practice of choosing elements for their meaning. A <nav> element is not a styled list. An <article> is not a box with a border. These elements carry machine-readable information about the role content plays in a document — information that browsers expose to assistive technology, that search engines use to understand page structure, and that future developers rely on when they open your codebase six months from now. That machine-readable role is exactly what powers ARIA landmark navigation: a correctly chosen <nav> or <main> element is already a landmark, with no additional attribute required.

The argument for semantic markup is not primarily a compliance argument. WCAG 2.2 success criterion 1.3.1 (Info and Relationships) does require that structural relationships conveyed visually also be conveyed programmatically — but that frames semantics as a checkbox. The real case is different: semantic structure is how you make the contract between your interface and your user legible. When you break that contract, users feel it, even if they can’t articulate why. When you honor it, interfaces disappear, and users focus on what they came to accomplish.

That disappearance — that frictionless quality — is what this site calls a rave.

What Semantic Elements Actually Mean

The HTML5 era introduced a set of sectioning and landmark elements that map to common page-level patterns. Understanding what each element means is a prerequisite for using them correctly. The WHATWG HTML specification defines each element’s semantics precisely; the summaries below are practical interpretations for practitioners.

<main>

<main> contains the primary content of the document — the part that is unique to this page and not repeated across your site. There should be exactly one <main> per document (though additional <main> elements can exist in a hidden state). Navigation, sidebars, headers, and footers are not part of <main>.

Screen reader users often jump directly to <main> to skip repeated navigation. If your <main> wraps the wrong content — or if you’ve omitted it entirely and wrapped everything in a generic <div id="content"> — you’ve broken the most efficient entry point into your page.

<nav> identifies a block of navigation links. Not every group of links qualifies — the spec notes it should be used “for major navigation blocks.” Footer links that repeat the site map, the primary site navigation, breadcrumbs, and in-page tables of contents are appropriate candidates. A list of three social icon links in a sidebar probably is not.

When you use multiple <nav> elements on a page (common when you have both site navigation and section navigation), label them distinctly with aria-label or aria-labelledby so screen reader users can distinguish them. Unlabeled multiple <nav> regions become “navigation, navigation, navigation” in a landmarks list — identical entries that tell users nothing.

These elements function at two scopes. At the document level, <header> typically contains the site logo, primary navigation, and introductory branding. <footer> at the document level contains site-wide information: copyright, legal links, contact information.

But both elements are also valid within sectioning content. An <article> can have its own <header> (byline, publication date, title) and its own <footer> (tags, related content, author bio). When <header> and <footer> appear inside a sectioning element rather than directly inside <body>, they are scoped to that section — they do not carry the landmark role that the document-level equivalents do. This is a distinction that matters for assistive technology: the ARIA banner role (associated with a top-level <header>) and contentinfo role (associated with a top-level <footer>) are exposed only when those elements are direct children of <body> or are outside sectioning elements.

<article>

<article> represents a self-contained composition that could, in principle, be distributed independently. A blog post is the obvious case, but the spec is broader: a product card in an e-commerce listing, a comment in a thread, a forum post, and a social media update are all valid uses. The key test is independent distribution — does this piece of content make sense on its own?

Articles can nest. A blog post is an <article> containing a list of comments, each of which is also an <article>. The nesting communicates a relationship: these inner articles are related to the outer one.

<section>

<section> is the most misused of the sectioning elements. It is not a semantic <div>. The spec is specific: a section represents a thematic grouping of content, typically with a heading. If the content you’re wrapping does not have a heading and does not represent a distinct thematic unit within the document, <div> is the right element.

The practical test from the WHATWG spec: would this content appear in a hypothetical document outline? If yes, consider <section>. If not, <div>.

<aside>

<aside> contains content that is tangentially related to the surrounding content. Pull quotes, related article links, advertising, biographical sidebars, and glossary callouts are appropriate. An aside is content that could be removed without changing the main argument of the surrounding text.

Document Structure: Getting the Outline Right

The document outline algorithm — the browser’s way of inferring a hierarchy from your heading levels and sectioning elements — has a troubled history. The HTML5 outline algorithm introduced the idea that headings inside sectioning elements reset the outline depth, meaning you could theoretically start every <section> with an <h1>. That algorithm was never implemented by browsers or assistive technology. It was officially removed from the HTML specification in 2022.

What this means in practice: heading levels still matter. The heading hierarchy — <h1> through <h6> — should reflect the document’s content hierarchy, independent of which sectioning elements you use. A well-structured page has one <h1> (the page’s main topic), <h2> elements for major sections, <h3> for subsections of those, and so on. Skipping levels (jumping from <h2> to <h4>) creates an outline that is harder for screen reader users to navigate and harder for search engines to parse.

Sectioning elements do contribute to the document’s semantic structure — they create implicit sections that landmark navigation exposes — but they are not a substitute for a logical heading hierarchy.

Code Examples: Patterns That Work and Patterns That Don’t

A Typical Article Page

The following structure represents a well-organized article page. Note how <main> wraps only the primary content, the article has its own <header>, and the sidebar is marked as <aside>:

<body>
  <header>
    <a href="/">
      <img src="/logo.svg" alt="UI Brainstorms & Design">
    </a>
    <nav aria-label="Site navigation">
      <ul>
        <li><a href="/articles/">Articles</a></li>
        <li><a href="/about/">About</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <article>
      <header>
        <h1>Semantics, HTML, and Document Structure</h1>
        <p>Published <time datetime="2024-03-15">March 15, 2024</time></p>
      </header>

      <section>
        <h2>The Case for Meaning Over Appearance</h2>
        <p><!-- article content --></p>
      </section>

      <footer>
        <p>Filed under: <a href="/categories/web-standards/">Web Standards</a></p>
      </footer>
    </article>

    <aside aria-label="Related articles">
      <h2>Keep reading</h2>
      <ul>
        <li><a href="/articles/aria-roles/">ARIA Roles in Practice</a></li>
      </ul>
    </aside>
  </main>

  <footer>
    <nav aria-label="Footer navigation">
      <ul>
        <li><a href="/about/">About</a></li>
        <li><a href="/contact/">Contact</a></li>
      </ul>
    </nav>
    <p><small>&copy; 2024 UI Brainstorms &amp; Design</small></p>
  </footer>
</body>

A Common Mistake: Structural Divitis in Disguise

The failure mode that semantic HTML is supposed to solve did not disappear when HTML5 introduced new elements — it migrated. Many codebases have replaced <div class="content"> with <section> and <div class="nav-container"> with <nav> while keeping the same undifferentiated structure. Here is what this looks like:

<!-- Incorrect: section used as a styling wrapper, no heading, no thematic grouping -->
<section class="hero-wrapper">
  <div class="hero-inner">
    <section class="hero-text">
      <p>Welcome to our site.</p>
    </section>
    <section class="hero-image">
      <img src="/hero.jpg" alt="">
    </section>
  </div>
</section>

This is <div> soup wearing a semantic costume. The <section> elements here have no headings, no distinct thematic grouping, and no business being sections. The correct approach uses <div> for the layout wrappers and reserves sectioning elements for content that genuinely divides the document into meaningful parts.

A Comment Thread with Nested Articles

This pattern, taken from the spec itself, shows how nesting communicates relationship:

<article>
  <header>
    <h1>The Trouble with Outline Algorithms</h1>
    <p>By <span>The editors</span></p>
  </header>

  <p><!-- post body --></p>

  <section>
    <h2>Comments</h2>

    <article id="comment-1">
      <header>
        <h3>Comment by Alex</h3>
        <time datetime="2024-03-16T10:00">March 16</time>
      </header>
      <p>The history of the outline algorithm is fascinating...</p>
    </article>

    <article id="comment-2">
      <header>
        <h3>Comment by Jordan</h3>
        <time datetime="2024-03-16T14:30">March 16</time>
      </header>
      <p>Agreed — and yet so many people still write <code>h1</code> inside every section.</p>
    </article>
  </section>
</article>

Each comment is a self-contained piece of content (<article>) nested inside a comments <section>, which is itself nested inside the post <article>. The heading hierarchy reflects the nesting: h1 for the post, h2 for the comments section, h3 for each comment.

The Accessibility Payoff

Screen reader users navigate by landmarks and headings. The WAI-ARIA Authoring Practices describes this clearly: experienced screen reader users routinely open a page’s landmark list or headings list first, scanning for the section they need before reading any content. This is equivalent to how sighted users visually scan a page — except it only works when the underlying structure is present.

When semantic landmarks are missing, navigation degrades to linear reading: the screen reader announces every element in source order, from the site header through navigation through disclaimers to the content the user actually wanted. On a content-heavy page, this is the assistive technology equivalent of requiring sighted users to read every sidebar ad before seeing the article.

The specific mappings matter. HTML elements expose implicit ARIA roles that browsers communicate to the accessibility tree:

  • <main>role="main"
  • <nav>role="navigation"
  • <header> (document-level) → role="banner"
  • <footer> (document-level) → role="contentinfo"
  • <aside>role="complementary"
  • <section> with an accessible name → role="region"

These roles are what screen readers announce. When you use the correct HTML element, you get the correct role for free, without any ARIA attributes. When you use a <div> and add role="navigation" manually, you’re doing the same job twice — and ARIA applied to <div> elements is easier to get wrong, because you lose the browser’s built-in handling.

The principle stated in the W3C’s first rule of ARIA use: if you can use a native HTML element with the semantics and behavior already built in, do that. ARIA is for filling gaps, not replacing what HTML already provides.

Keyboard navigation also benefits. The <nav> landmark lets keyboard-only users jump to navigation blocks. Proper heading structure lets them skip to specific sections. <main> lets them bypass repeated content entirely. These are not features you build — they are features the browser gives you when your markup is correct.

SEO and Machine-Readable Structure

Search engines parse HTML to understand what content is about and how it relates to other content. Semantic structure contributes to that understanding in ways that classless <div> hierarchies cannot.

Google’s crawlers use heading structure to infer topic hierarchy. An <h1> that accurately describes page content, followed by <h2> elements that subdivide the topic into logical sections, produces a page outline that aligns with how the content is indexed. Pages with well-structured headings tend to generate more accurately targeted featured snippets and structured search results — not because semantic HTML directly triggers a ranking boost, but because it makes content structure legible to systems that extract structured information.

Structured data markup (JSON-LD, microdata) works alongside semantic HTML, not instead of it. A well-structured <article> with correct heading hierarchy and publication dates in <time> elements provides a reliable base that structured data can annotate. When the underlying HTML contradicts the structured data — when the page’s visual hierarchy has nothing to do with its heading structure — structured data becomes unreliable.

The <article> element carries particular significance for content discovery. Browsers and third-party applications (read-it-later services, browser reading modes, RSS aggregators) use <article> as a heuristic for “this is the primary content.” Safari’s Reader View, Firefox Reader Mode, and tools like Readability depend on these signals. Pages that mark up their content correctly present cleanly in these contexts; pages that wrap everything in <div> elements risk garbled or incomplete extraction.

When You Get This Right

The payoff for semantic HTML is not visible in a design review. It doesn’t appear in a sprint demo. Nobody schedules a celebration when the landmark regions are correctly labeled. This is precisely what makes it easy to defer — and why so many production sites ship with landmark soup, heading levels chosen for visual weight rather than document hierarchy, and <div> wrappers performing work that semantic elements would do for free.

But users feel it. The screen reader user who opens your site and finds a clean landmark list, jumps to <main>, and gets directly to the content they wanted — that user had an effortless experience. The keyboard-only user who tabs through your navigation without being trapped — effortless. The reader mode user who pulls up your long-form article on a cluttered page and gets the clean text with none of the surrounding noise — effortless.

Effortless experiences are the ones that generate raves. They are also, not incidentally, the experiences that generate return visits, referrals, and the kind of word-of-mouth that no ad campaign can buy.

Semantic HTML is a foundational craft decision. It costs nothing at the implementation stage — choosing <nav> over <div> is the same amount of work. The cost comes later, when you have to retrofit structure onto a codebase that never had it: auditing heading hierarchies, identifying which divs should have been landmarks, adding ARIA attributes to recover information that HTML would have provided automatically.

The decision to write semantic markup is a decision to respect every user who will interact with your interface — including users you will never observe, using tools you may never test with, in contexts you cannot anticipate. That respect is the foundation of frontend craft. It is also what separates interfaces that merely function from interfaces that feel considered, that feel built for actual humans.

That is when users stop noticing the interface at all. That is when they rave.


Further reading: