{"id":"b38lrdvxg9glf7p","title":"Semantic HTML Landmarks Search Engines Actually Read","slug":"semantic-html-landmarks-beyond-divs","summary":"I stopped wrapping everything in divs when I saw how much crawl clarity I was leaving on the table. Landmarks are cheap markup with real SEO upside.","imageUrl":"https://briancrabtree.me/images/journal-semantic-html-landmarks-beyond-divs.webp","category":"HTML","date":"2025-12-29T18:00:00.000Z","featured":false,"likes":40,"author":"Brian Crabtree","content":"<h2>Why div soup still wins by default</h2>\n\n<p>Every greenfield project starts with good intentions and ends with a forest of anonymous containers. I have done it too. Divs carry no meaning, impose no contract, and never argue with the designer. That convenience hides a cost: crawlers and assistive tech both guess structure from class names that were never meant to be a spec.</p>\n\n<p>Semantic HTML is not nostalgia for XHTML. It is a performance and discovery layer. A single main element tells everyone where the primary content lives. nav and footer boundaries reduce duplicate-link noise in sitemaps built by tools that still scrape the DOM when JSON-LD is missing.</p>\n\n<p>I still see components named SidebarInnerWrapper with no landmark because the framework starter never mentioned aside. Rename the component if you want, but output aside in the DOM when the content is tangential to the article. Search engines and screen readers consume the DOM, not your Storybook labels.</p>\n\n<pre><code>&lt;header&gt;...&lt;/header&gt;\n&lt;nav aria-label=\"Main\"&gt;...&lt;/nav&gt;\n&lt;main id=\"main\"&gt;\n  &lt;article&gt;\n    &lt;h1&gt;Post title&lt;/h1&gt;\n    ...\n  &lt;/article&gt;\n&lt;/main&gt;\n&lt;footer&gt;...&lt;/footer&gt;</code></pre>\n\n<p><figure>\n  <img src=\"/images/journal-inline-semantic-landmarks.webp\" alt=\"Page structure diagram with header nav main article footer landmarks labeled\" width=\"1200\" height=\"675\" loading=\"lazy\" />\n  <figcaption>Landmarks help crawlers and screen readers map the page — div soup does not.</figcaption>\n</figure></p>\n\n<h2>Landmarks that change crawl behavior</h2>\n\n<p>header, main, nav, aside, article, section, and footer are not decorative. They establish reading order for screen readers and give search engines stable anchors when titles repeat across templates. I map one main per page, one nav for global wayfinding, and article for each journal entry or case study body.</p>\n\n<p>section without a heading is a lint smell in my reviews. If you cannot name the section in an h2, it probably should be a div or merge upward. Headings form the outline Google uses when it synthesizes sitelinks and featured snippets from on-page hierarchy.</p>\n\n<p>Duplicate nav blocks in header and footer are fine when one is primary wayfinding and the other is legal links. I avoid two nav elements with identical link sets; that confuses outline algorithms and wastes crawl budget on redundant anchors.</p>\n\n<h2>Headings are an API, not typography</h2>\n\n<p>Designers want h3 sized like an h1. I push back. Skipping levels breaks the document outline and confuses parsers that infer FAQ blocks from h2 followed by short paragraphs. I keep one h1, logical h2 sections, and h3 only when the parent section truly branches.</p>\n\n<p>When a React app renders headings client-side only, crawlers may see a flash of empty outline on first fetch unless prerender or SSR supplies the tree. That is why this site ships static shells for journal routes: the semantics exist before hydration, not after.</p>\n\n<p>Template partials should enforce heading level in the API: a Section component that requires title prop and renders h2. That keeps React from scattering h4 tags because the designer picked a smaller token.</p>\n\n<h2>Forms, buttons, and interactive semantics</h2>\n\n<p>Clickable divs still appear in production code because cursor:pointer is faster than learning button defaults. I convert them. Native buttons participate in focus order, activate with keyboard, and expose role without aria hacks. The same applies to links versus buttons: href means navigation, button means action.</p>\n\n<p>Labels tied to inputs with for and id are free accessibility wins that also reduce support tickets on mobile where tap targets overlap. I treat that as HTML performance: fewer confused users, fewer bounce signals, cleaner analytics.</p>\n\n<p>Autocomplete attributes on login and checkout forms are not optional polish. Browsers use them to speed input; I map username, email, and street-address correctly and watch autofill-related support tickets drop.</p>\n\n<h2>Microdata without the microdata headache</h2>\n\n<p>JSON-LD in the head handles rich results for articles and organization schema. Semantic landmarks still matter for pages where structured data is thin. A proper article element wrapping publish date and author byline gives parsers redundant signals when JSON-LD fails validation.</p>\n\n<p>I do not chase every schema type. I nail Article, WebSite, and BreadcrumbList where they map to real UI. The DOM and the JSON should tell the same story, not two competing fiction novels.</p>\n\n<p>When clients ask for FAQ rich results, I build real h2 plus short answer paragraphs in HTML instead of accordion-only widgets that hide text until click. Visible copy wins more often than clever UI.</p>\n\n<h2>Refactors that do not require a rewrite</h2>\n\n<p>You can migrate incrementally. Pick the highest-traffic template, add landmarks, fix heading order, and ship. Measure Search Console coverage and accessibility audits on that URL pattern before touching the long tail. Most teams overestimate the effort because they bundle semantic HTML with a framework migration.</p>\n\n<p>On client work I run a ten-minute DOM audit: count divs without class purpose, list heading jumps, verify one main. Fixes are usually an afternoon, not a quarter.</p>\n\n<p>I keep a checklist in CI: axe on PR for changed templates, plus a grep for div role=button without keyboard tests. Semantic fixes are boring to automate and high leverage.</p>\n\n<h2>What I ship on this site</h2>\n\n<p>briancrabtree.me uses semantic landmarks everywhere the journal and marketing shells render. Journal entries are article inside main, global chrome is nav and header, footers carry secondary links without stealing internal link equity from the body.</p>\n\n<p>If your stack is div-heavy, send a URL. I will mark up the template once and hand you the pattern your team can copy. Structure is still the cheapest SEO lever we have.</p>\n\n<p>Landmarks also help future you when the marketing site becomes ten locales. One main per language URL, translated nav labels, consistent article wrappers. The refactor cost stays flat because structure was never accidental. For a related angle I keep coming back to, see <a href=\"/journal/skip-links-keyboard-nav-spa/\">Skip Links and Keyboard Nav on SPAs</a>.</p>","tags":["semantic-html","accessibility","seo"],"views":130}