What "Semantic" Means
A semantic element is one whose name describes what its content is. <nav> says "this is navigation". <table> says "this is tabular data". <div>, by contrast, says nothing at all — it is a generic box, deliberately meaningless, useful precisely because it carries no baggage.
The two blocks of markup below produce pages that look identical. Give both the same stylesheet and no visitor could tell them apart. The difference is entirely in what they communicate to software: the first is a page whose regions have names, the second is a stack of anonymous boxes that a machine can only guess at.
It is worth saying plainly what semantic elements do not do: they do not style anything. <header> does not give you a coloured banner and <nav> does not lay your links out in a row. They behave as plain block containers, exactly like a <div>, and all the visual design is still your CSS. What you gain is meaning, and meaning is what everything downstream depends on.
<!-- Semantic: every region has a name -->
<header>
<h1>Robotics Club</h1>
<nav>...</nav>
</header>
<main>
<article>...</article>
</main>
<footer>...</footer>
<!-- "div soup": identical on screen, meaningless to software -->
<div class="header">
<div class="title">Robotics Club</div>
<div class="nav">...</div>
</div>
<div class="main">
<div class="article">...</div>
</div>
<div class="footer">...</div> Why div-for-Everything Is a Real Problem
The strongest reason is navigation for people who cannot see the page. Screen readers build a list of landmarks from semantic elements — banner, navigation, main, complementary, content information — and let the user jump straight between them with a single keystroke. That is how a blind visitor skips your menu and gets to the content, which is the equivalent of your eye jumping past a header you have seen a hundred times. A page built from <div> elements has no landmarks, so there is nothing to jump to. The only way through is from the very top, every time, on every page.
The second reason is that search engines and other automated readers use structure to decide what a page is about. Content inside <main> is the page's subject; content inside <nav> and <footer> is repeated furniture that appears on every page. When everything is a div, that distinction has to be inferred, and inference is less reliable than being told.
The third reason is the one you will feel yourself, in about three weeks. A file of eighty <div> tags with a wall of closing tags at the bottom is genuinely hard to edit — you cannot tell which </div> belongs to what, and deleting the wrong one breaks the layout in a way that takes half an hour to trace. When the closing tag says </footer>, you know exactly what it closed.
None of this means <div> is bad. It is the right element when you need a box purely to hang CSS on and no semantic element fits — a wrapper for a grid, a container for spacing. The rule is: reach for the element that describes the content, and fall back to <div> only when nothing does.
- Screen reader users can jump between landmarks; a page of divs offers none
- Search engines can tell your content from your site furniture
- Browsers' reader modes and "save for later" tools use semantics to find the article
- Closing tags become self-documenting, so large files stay editable
- New team members can read your structure without reading your CSS
<div>stays the correct choice when you need a box and no semantic element applies
- You can see landmarks for yourself without installing a screen reader. Chrome and Firefox Developer Tools both include an accessibility panel showing the tree of landmarks and headings a page exposes. Try it on a page you have built — if the tree is nearly empty, that is what an assistive technology user gets.
The Four Landmarks Every Page Needs
<header> is the introductory block at the top: site name, logo, and usually the main navigation. <nav> wraps a block of major navigation links. <main> holds the content unique to this page — everything that is not repeated on every other page. <footer> holds the closing block: copyright, contact details, secondary links.
<main> has one rule that the others do not: a page should contain only one, and it must not be nested inside <article>, <section>, <header>, <nav>, <aside> or <footer>. It marks the one region a "skip to content" link should jump to, so having two would defeat the purpose. It is also the element that makes a skip link — the first thing a keyboard user tabs to on a well-built site — actually work.
<nav> is over-applied. It is meant for major navigation blocks: your main menu, a table of contents, breadcrumbs. It is not for every group of links on the page. Three links in a paragraph of text do not need it, and a footer full of links usually does not either — a screen reader that announces six separate navigation landmarks has been made less useful, not more. If you genuinely have two, label them with aria-label so they can be told apart.
<header> and <footer> are not restricted to the page level. Each can also appear inside an <article> or a <section>, where it means the introduction or the closing block of that piece of content — a post's byline and date, for instance. Only the ones that are direct children of <body> become page-level landmarks.
<body>
<!-- Skip link: the first thing a keyboard user reaches -->
<a href="#content" class="skip-link">Skip to main content</a>
<header>
<h1>Robotics Club</h1>
<nav aria-label="Main">
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="events.html">Events</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</nav>
</header>
<main id="content">
<h2>Annual Project Showcase</h2>
<p>Projects built by second-year students this semester.</p>
</main>
<footer>
<p>© 2026 Robotics Club</p>
</footer>
</body> - A skip link is a plain anchor pointing at your
<main>. It is usually hidden off screen with CSS and made visible when it receives keyboard focus. Without it, a keyboard-only visitor must Tab through your entire menu on every single page before reaching the content.
article, section, or div?
This is where people get stuck, so here is a test that resolves most cases. Ask: would this block still make sense on its own, lifted out of the page entirely? If yes, it is an <article>. A blog post, a news item, a product card, a single comment, a forum reply — each of those is complete in itself and could appear in a feed elsewhere without its surroundings.
If the block only makes sense as a part of this page — a themed chunk of it, with its own heading — it is a <section>. "Upcoming Events" and "How to Reach Us" on a club page are sections. The rule of thumb is that a <section> should have a heading; if you cannot think of a heading for it, it is probably not a section.
And if the block has no meaning of its own and exists only so you can hang CSS on it — a wrapper to centre things, a grid container — it is a <div>. Choosing <section> for that job is a common overcorrection once people learn about semantics, and it adds noise: a screen reader listing your regions now includes several that mean nothing.
The two can nest either way round, and both are correct in the right circumstances. A page section listing recent posts contains several article elements. A long article contains sections for its chapters, each with its own heading. Do not force one to always contain the other.
<main>
<!-- A themed part of this page: has a heading, not independent -->
<section>
<h2>Upcoming Events</h2>
<!-- Each event is self-contained: it could appear in a feed -->
<article>
<header>
<h3>Robotics Challenge</h3>
<p>Posted <time datetime="2026-02-18">18 February 2026</time></p>
</header>
<p>Teams of three. Bring your own chassis.</p>
<footer><a href="events/robotics.html">Full details</a></footer>
</article>
<article>
<h3>Coding Contest</h3>
<p>Three hours, four problems, individual entry.</p>
</article>
</section>
<!-- No meaning, purely a CSS wrapper: div is correct -->
<div class="two-column-grid">
<section>
<h2>How to Reach Us</h2>
<p>The lab is on the second floor of Block C.</p>
</section>
<aside>
<h2>Related</h2>
<p>Last year's project archive.</p>
</aside>
</div>
</main> <article>— makes sense lifted out of the page; a post, a card, a comment<section>— a themed part of this page, and it should have a heading<div>— no meaning at all, purely a hook for styling or layout<aside>— related but not essential; a sidebar, a pull quote, a "see also" box- When in doubt between
<section>and<div>, ask whether you can write a heading for it
<time datetime="2026-02-18">is worth adopting. The visible text can be written however you like — "18 February 2026", "last Tuesday" — while thedatetimeattribute gives machines an unambiguous value inyyyy-mm-ddform.
Converting div Soup, Step by Step
You do not need to memorise every element to write good semantic HTML. Build your page normally, then read through it once and ask of each container: is there an element whose name says what this is? Header, navigation, main content, footer, a self-contained item, a sidebar. Replace the ones that have an answer and leave the rest as divs.
Two elements are commonly misused during that pass, so it is worth knowing them. <address> is not for postal addresses in general — it means the contact details of the author of the nearest article or of the page as a whole. An address in your delivery-information table is just text. And <aside> means content tangentially related to what is around it; it does not mean "on the right-hand side", so a sidebar containing your main navigation is a <nav>, not an aside.
Run the example below and then look at it in your browser's accessibility panel. The same page written with divs would show an empty landmark list; this one shows a labelled structure someone could actually navigate.
HTML
<a href="#content" class="skip-link">Skip to main content</a>
<header class="site-header">
<h1>Robotics Club</h1>
<nav aria-label="Main">
<ul>
<li><a href="#content">Home</a></li>
<li><a href="#events">Events</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main id="content">
<section id="events">
<h2>Upcoming Events</h2>
<article>
<header>
<h3>Robotics Challenge</h3>
<p class="meta">
Posted <time datetime="2026-02-18">18 February 2026</time>
</p>
</header>
<p>Teams of three build a line-following robot in six hours.
Chassis and sensors are provided; bring your own laptop.</p>
<footer><a href="#events">Full rules and entry form</a></footer>
</article>
<article>
<h3>Coding Contest</h3>
<p>Four problems, three hours, individual entry. Open to all years.</p>
</article>
</section>
<section id="contact">
<h2>How to Reach Us</h2>
<p>The lab is on the second floor of Block C, open on Saturdays.</p>
</section>
</main>
<aside>
<h2>Related</h2>
<p>Browse last year's project archive.</p>
</aside>
<footer class="site-footer">
<p>© 2026 Robotics Club</p>
</footer> CSS
body {
font-family: system-ui, Arial, sans-serif;
line-height: 1.6;
margin: 0;
color: #222;
}
/* The skip link is hidden until it receives keyboard focus */
.skip-link {
position: absolute;
left: -9999px;
}
.skip-link:focus {
position: static;
display: inline-block;
padding: 8px 12px;
background: #ffe;
}
.site-header {
background: #7a0060;
color: #fff;
padding: 20px 24px;
}
.site-header h1 { margin: 0 0 8px; font-size: 1.4rem; }
.site-header a { color: #fff; }
nav ul {
list-style: none;
display: flex;
gap: 18px;
margin: 0;
padding: 0;
}
main, aside { padding: 24px; }
article {
border: 1px solid #e2e2e6;
border-radius: 8px;
padding: 16px 20px;
margin-bottom: 16px;
}
.meta { color: #666; font-size: 0.9rem; margin-top: 0; }
aside {
background: #faf6f9;
border-top: 1px solid #eee;
}
.site-footer {
background: #222;
color: #fff;
padding: 16px 24px;
font-size: 0.9rem;
} - Press Tab as soon as the example loads. The skip link appears, and pressing Enter jumps you straight past the menu to the content. That single pattern — a skip link, a labelled nav and a real
<main>— is most of what basic accessibility asks of your HTML.
