Semantic HTML: Build Websites That Work Without CSS

Semantic HTML is the practice of writing markup that describes the meaning of your content, not just how it looks. When you use semantic HTML, your website has a solid foundation that works for everyone, regardless of how they access it.

Most developers learn HTML as a way to make things appear on screen. But the real power of HTML comes from writing markup that makes sense on its own, even without stylesheets (CSS) or JavaScript. This fundamental practice separates good web design from bad.

Why semantic HTML matters

Your HTML is the foundation of everything on the web. Before your CSS loads, before JavaScript runs, before images appear, your HTML is there. And for some users, that HTML is all they get.

Someone on a slow connection might see your content before your styles load. Someone using a screen reader experiences your site through the structure of your markup. Search engines read your HTML to understand what your page is about. When you write semantic HTML, you build something that works for all of these scenarios.

Dan Cederholm, a designer known for his attention to craft, wrote about this idea years ago. He asked a simple question: “if your style sheet doesn’t load, what kind of experience are you serving somebody?” This might sound like a minor detail, but it reveals something deeper about web design.

Good craft shows up in the parts you don’t see. When you buy well-made furniture, you can tell someone thought about the joins and the structure, even if those details are hidden. The same is true for websites. The quality of your HTML matters, whether users see it directly or not.

The difference between semantic and non-semantic HTML

Non-semantic HTML uses generic containers like <div> and <span> for everything. These elements don’t tell you anything about the content inside them. They’re just boxes.

Semantic HTML uses elements that describe what the content is: <header>, <nav>, <article>, <section>, <aside>, <footer>. These elements have meaning built in. When you use them correctly, your markup tells a story about your content structure.

Here’s what this looks like in practice. A non-semantic approach might look like this:

<div class="header">
  <div class="nav">
    <div class="nav-item">Home</div>
    <div class="nav-item">About</div>
  </div>
</div>
<div class="content">
  <div class="post">
    <div class="title">Article Title</div>
    <div class="body">Article content here</div>
  </div>
</div>

The semantic version tells you what everything is:

<header>
  <nav>
    <a href="/">Home</a>
    <a href="/about">About</a>
  </nav>
</header>
<main>
  <article>
    <h1>Article Title</h1>
    <p>Article content here</p>
  </article>
</main>

The second version works better for screen readers, search engines, and anyone who needs to understand your page structure without seeing the visual design.

Signs your HTML needs better semantics

You’ll know your markup needs work if you can answer yes to any of these questions:

Your site uses <div> elements for almost everything. Generic containers have their place, but if your entire layout is div soup, you’re missing opportunities to add meaning.

You rely on CSS classes to communicate structure. Classes like “header” or “navigation” or “sidebar” should really be semantic elements instead.

Your document doesn’t make sense when you turn off CSS. Try it right now: disable your stylesheet and look at your page. Does the content flow logically? Can you tell what’s important? If not, your HTML needs more structure.

Screen reader users report problems navigating your site. If people using assistive technology have trouble finding navigation, skipping to content, or understanding page structure, your markup is probably too generic.

You have trouble explaining what a section of your page is for. If you can’t quickly say “this is the main navigation” or “this is an article” or “this is supplementary content,” you probably haven’t marked it up correctly.

How to write better semantic HTML

Start with the document outline. Before you write any markup, think about the structure of your content. What are the major sections? What’s the hierarchy? Your HTML should reflect this natural organization.

Use heading levels correctly. Your page should have one <h1> that describes the main topic. Sub-sections get <h2> tags. Sections within those get <h3> tags, and so on. Don’t skip levels, and don’t choose heading levels based on how big you want the text to be.

Choose elements based on meaning, not appearance. When you need to mark up navigation, use <nav>. For your main content area, use <main>. For self-contained content like blog posts, use <article>. For supplementary content, use <aside>. Let CSS handle how these elements look.

Test without CSS. This is the single best way to check your semantic HTML. Remove your stylesheet and look at your page. Does the content make sense? Is the hierarchy clear? Can you understand the page structure? If yes, your semantics are working.

Use landmark roles naturally. Modern semantic elements like <header>, <nav>, <main>, and <footer> automatically create ARIA landmark roles. Screen reader users can jump between these landmarks to navigate your site quickly. But they only work if you use the right elements.

Keep the DOM clean and readable. When another developer looks at your HTML, they should be able to understand the page structure quickly. This is what Dan Cederholm meant when he talked about craft in the details you don’t see. A clean document structure is a sign of quality work.

Think about the experience without your design. Ethan Marcotte, who created responsive web design, has talked about how craft shows up in unexpected places. In a conversation about web design quality, he noted: “if your style sheet doesn’t load, what kind of experience are you serving somebody? This is, that might feel like detail work or boring work to some people, but like he always talked about it as if when you buy really beautifully made pieces of woodworking, there’s craft in the joins, right? Like these fundamental pieces that you don’t often see, but you can tell that somebody thought about that.”

This idea connects to something deeper about web development. The web is built on layers. Your HTML is the foundation. Your CSS is the presentation. Your JavaScript adds behavior. Each layer should work on its own, and each layer should enhance what came before. This is called progressive enhancement, and it starts with solid semantic HTML.

A real example

Let’s look at a blog layout. Here’s how you might structure it semantically:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Blog Post Title - Site Name</title>
</head>
<body>
  <header>
    <h1>Site Name</h1>
    <nav>
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/about">About</a></li>
        <li><a href="/blog">Blog</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <article>
      <header>
        <h1>Blog Post Title</h1>
        <p>Published on <time datetime="2026-02-23">February 23, 2026</time></p>
      </header>

      <p>First paragraph of content...</p>

      <h2>Section Heading</h2>
      <p>More content...</p>

      <h2>Another Section</h2>
      <p>Even more content...</p>

      <footer>
        <p>Tags: <a href="/tag/html">HTML</a>, <a href="/tag/accessibility">Accessibility</a></p>
      </footer>
    </article>

    <aside>
      <h2>Related Posts</h2>
      <ul>
        <li><a href="/post-1">Related Post 1</a></li>
        <li><a href="/post-2">Related Post 2</a></li>
      </ul>
    </aside>
  </main>

  <footer>
    <p>&copy; 2026 Site Name. All rights reserved.</p>
  </footer>
</body>
</html>

Notice how this markup tells a story even without any CSS. The structure is clear: site header, main content with an article and sidebar, site footer. The headings create a logical outline. The navigation is marked as navigation. The timestamps use the <time> element with a machine-readable datetime attribute.

This is semantic HTML in practice. When CSS loads, you can style these elements however you want. But the foundation is solid regardless of styling.

FAQs

Semantic HTML is the practice of using HTML elements that describe the meaning of content, not just its appearance. Instead of using generic <div> elements everywhere, semantic HTML uses elements like <header>, <nav>, <article>, and <footer> that tell browsers, assistive technology, and developers what each part of a page is for.

Semantic HTML creates websites that work better for everyone. Screen readers can navigate your site more easily when you use meaningful elements. Search engines understand your content better when your markup has clear structure. Developers can maintain your code more easily when the HTML is self-documenting. Plus, semantic elements automatically provide accessibility features that you’d have to add manually with divs and ARIA attributes.

Yes. Search engines use HTML structure to understand your content. When you use heading hierarchies correctly, mark up your navigation properly, and structure your content with semantic elements, search engines can better determine what your page is about and how important different sections are. While semantic HTML alone won’t make your site rank higher, it’s part of a foundation that helps search engines index your content correctly.

If your site has good semantic HTML, users will still be able to read and navigate your content even without CSS. The text will appear in a logical order, headings will show content hierarchy, links will be clickable, and navigation will be usable. This matters more than you might think, because some users disable CSS, some use browsers with limited CSS support, and everyone experiences moments when stylesheets fail to load due to network issues.

Start with these: <header> for site or section headers, <nav> for navigation, <main> for your primary content, <article> for self-contained content, <section> for thematic groupings, <aside> for supplementary content, and <footer> for site or section footers. Also use heading elements (<h1> through <h6>) correctly to create a logical document outline, and use <p> for paragraphs instead of <div> or <br> tags.

The simplest test: turn off CSS and look at your page. If the content still makes sense, your structure is clear, and you can navigate the page easily, your semantic HTML is working. You can also use the Web Developer extension in Chrome or Firefox to disable styles quickly. Screen reader testing is even better, if you have access to tools like NVDA, JAWS, or VoiceOver.

Semantic HTML is one part of web accessibility. Using meaningful HTML elements creates a foundation that assistive technology can understand. But accessibility goes further, including things like color contrast, keyboard navigation, ARIA attributes for complex interactions, and alternative text for images. Think of semantic HTML as the baseline, good markup makes accessibility much easier to achieve.

Yes. Generic containers have their place. Use <div> and <span> when you need to group elements purely for styling or JavaScript purposes and there’s no semantic element that fits. The goal isn’t to eliminate divs entirely, but to use semantic elements whenever they accurately describe your content.

The takeaway

Semantic HTML is the foundation of good web design. When you write markup that describes meaning, you create websites that work for everyone, regardless of how they access your content.

This approach requires thinking about structure before styling. It means choosing elements based on what your content is, not how you want it to look. It means testing your pages without CSS to ensure they make sense on their own.

The craft of web development shows up in these fundamental details. When you build with semantic HTML, you’re building something resilient that works across devices, connections, and assistive technologies. You’re working with the web’s grain instead of against it.

Start with your next project. Think about the document structure before you write any markup. Use heading levels correctly. Choose semantic elements over generic divs. Test without stylesheets. These practices take a little more thought upfront, but they create websites that work better for everyone.

The web is for everyone. Your HTML should be too.

Kendall Guillemette | Feb 23, 2026

The show can be found wherever you get your podcasts:

Real conversations, straight to your inbox.
Subscribe for new episodes and more.