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>© 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
<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.<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.<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
