Overview
A blog homepage is one of the clearest real-world cases for semantic sectioning elements, because a real blog homepage genuinely has multiple, independent kinds of content on one page: a masthead, a featured story, a list of recent posts, and supporting information off to the side. Each of those deserves its own landmark, and HTML5 has a specific element for almost every one of them.
This tutorial builds that homepage using <header>, <main>, <article>, <aside>, and <footer>, adds a genuine data table for post statistics (not a table used for layout — that old practice is exactly what semantic HTML replaced), and embeds a multimedia highlight so the page isn't purely text.
- A site
<header>with the blog name and primary navigation. - A featured
<article>with a hero image, headline, and excerpt. - A list of recent posts, each its own
<article>, inside a labeled<section>. - A real
<table>of post statistics — title, author, published date, and read time. - A multimedia highlight using an embedded
<video>element. - An
<aside>sidebar for categories and a closing<footer>.
Prerequisites
- Semantic landmark elements — header, main, section, article, footer (built in the Portfolio project).
- No prior table knowledge needed — this project introduces
table,thead,tbody,tr,th, andtdfrom scratch. - How
<img>and itssrc/altattributes work. - General attribute syntax, since
<video>introduces a couple of new ones (controls,poster).
Project Structure
The page is one file, blog.html, with three top-level regions inside <body>: <header> (site name and nav), <main> (the featured article, the recent-posts list, and the stats table), and <footer>. An <aside> sits alongside <main> as a sibling, holding content that is related to the blog but not part of its primary content stream — exactly what a sidebar of categories is.
The recent posts are wrapped in a <section id="recent"> containing several <article> elements, one per post — each post genuinely stands alone (it has its own title, author, and content), which is the textbook case for <article>. The stats table, by contrast, uses <table> because its data has one property nothing else on the page does: rows and columns where each cell's meaning depends on both its row and column header simultaneously. That is what a table is for, and it is the reason tables were pulled out of general page-layout duty once CSS could handle layout instead.
Step 1: Scaffold the Page and Site Header
Start with the standard boilerplate and the site header — a blog name and a short primary navigation, both landmark content for the whole page rather than tied to one post.
<!doctype html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>The Weekly Byte - A Web Development Blog</title> <meta name="description" content="Weekly articles on frontend development, accessibility, and web performance."></head><body>
<!-- Site-wide banner: the blog's name and top-level nav, not tied to any one post --> <header> <h1>The Weekly Byte</h1> <nav> <ul> <li><a href="#featured">Featured</a></li> <li><a href="#recent">Recent Posts</a></li> <li><a href="#stats">Post Stats</a></li> </ul> </nav> </header>
<!-- <main> content and the <aside> sidebar are added in the steps that follow -->
</body></html>Step 2: Build the Featured Article
The featured article is the first thing inside <main>. It's wrapped in <article> rather than <section> because it is one specific, independently meaningful post — it would still make complete sense shared on its own as a link preview. The publish date uses <time datetime="..."> so both humans and machines (search engines, browsers) can parse it unambiguously, regardless of how it's displayed.
<!-- id="featured" is the target of the header's "Featured" nav link --><article id="featured"> <header> <!-- A nested <header> here scopes to this one article, not the whole page - it groups this post's own title/byline, distinct from the site-wide <header> above --> <h2>Why Semantic HTML Still Matters in 2026</h2> <p>By Priya Nandan — <time datetime="2026-08-01">August 1, 2026</time></p> <!-- datetime="2026-08-01" is the machine-readable date; the visible text can stay human-friendly --> </header> <img src="https://placehold.co/640x320" alt="Illustration of HTML tags forming a webpage structure"> <p> Div-and-span soup still works, technically — browsers don't refuse to render it. But every div you swap for a header, article, or nav is a small gift to search engines, screen readers, and the next developer who opens this file. </p></article>Step 3: List Recent Posts
Recent posts follow, grouped in a <section> since the whole block shares one theme ("recent posts") even though each post inside it also gets wrapped in its own <article>. Add this section directly after the featured article, still inside <main>.
<!-- id="recent" is the target of the header's "Recent Posts" nav link --><section id="recent"> <h2>Recent Posts</h2>
<!-- Each post is its own <article>: standalone, independently meaningful content --> <article> <h3>Flexbox vs. Grid: When to Reach for Which</h3> <p>By Rohan Mehta — <time datetime="2026-07-28">July 28, 2026</time></p> <p>A practical comparison of the two layout models, with real examples of each.</p> <a href="#">Read more →</a> </article>
<article> <h3>A Beginner's Guide to ARIA Landmarks</h3> <p>By Asha Verma — <time datetime="2026-07-21">July 21, 2026</time></p> <p>How ARIA roles fill the gaps that native HTML elements don't cover.</p> <a href="#">Read more →</a> </article>
<article> <h3>Speeding Up Page Loads With Lazy-Loaded Images</h3> <p>By Karan Singh — <time datetime="2026-07-14">July 14, 2026</time></p> <p>The loading="lazy" attribute, explained with before-and-after load times.</p> <a href="#">Read more →</a> </article></section>Step 4: Add a Post Stats Table
A table is the right choice for the post statistics block below, because each cell's meaning depends on both its row (which post) and column (which metric) — that two-axis relationship is exactly what <table>, with proper <th> headers, communicates to both sighted users and screen readers. <thead> separates the header row from the data rows in <tbody>, and scope="col" tells assistive tech that each <th> is a column header, not just bold text.
<!-- id="stats" is the target of the header's "Post Stats" nav link --><section id="stats"> <h2>Post Stats</h2> <table> <!-- <thead> holds the column headers, kept separate from the data rows in <tbody> --> <thead> <tr> <th scope="col">Title</th> <!-- scope="col" tells screen readers this header applies to the whole column below it --> <th scope="col">Author</th> <th scope="col">Published</th> <th scope="col">Read Time</th> </tr> </thead> <tbody> <tr> <td>Why Semantic HTML Still Matters in 2026</td> <td>Priya Nandan</td> <td>Aug 1, 2026</td> <td>6 min</td> </tr> <tr> <td>Flexbox vs. Grid: When to Reach for Which</td> <td>Rohan Mehta</td> <td>Jul 28, 2026</td> <td>8 min</td> </tr> <tr> <td>A Beginner's Guide to ARIA Landmarks</td> <td>Asha Verma</td> <td>Jul 21, 2026</td> <td>5 min</td> </tr> </tbody> </table></section>Step 5: Embed a Multimedia Highlight
The multimedia highlight uses <video> with the controls attribute, which tells the browser to show its built-in play/pause/volume UI rather than requiring custom JavaScript controls. The poster attribute supplies an image shown before playback starts — useful here since no actual video file is attached, so the poster is effectively what displays.
<section id="video-highlight"> <h2>This Week's Highlight</h2> <!-- controls shows the browser's built-in play/pause/volume UI - no custom JS needed --> <!-- poster is the image shown before playback starts (and here, since no <source> is attached, effectively the only thing shown) --> <video controls poster="https://placehold.co/640x360" width="640" height="360"> <!-- A real deployment would add: <source src="highlight.mp4" type="video/mp4"> --> Your browser does not support embedded video. <!-- Fallback text, shown only if the browser can't render <video> at all --> </video></section>Step 6: Add a Sidebar and Footer
Last, the sidebar and footer. <aside> is the correct element for the categories list because it is tangentially related content, not part of the main article flow — removing it wouldn't break the meaning of any post. <aside> sits next to <main> as a sibling, not inside it.
<!-- <aside> for content that's related but not part of the primary article flow; sits as a sibling of <main>, not nested inside it --><aside> <h2>Categories</h2> <ul> <li><a href="#">HTML & CSS</a></li> <li><a href="#">JavaScript</a></li> <li><a href="#">Accessibility</a></li> <li><a href="#">Performance</a></li> </ul></aside>
<!-- Page-wide closing content, so it's a sibling of <header> and <main>, not nested inside them --><footer> <p>© 2026 The Weekly Byte. All rights reserved.</p></footer>Complete Code
Here is the full homepage assembled in order, plus a small stylesheet for the header, table, video, and sidebar.
<!doctype html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>The Weekly Byte - A Web Development Blog</title> <meta name="description" content="Weekly articles on frontend development, accessibility, and web performance."> <style> * { box-sizing: border-box; } body { font-family: Arial, Helvetica, sans-serif; margin: 0; color: #222; line-height: 1.6; background: #fafafa; } header { background: #2b3a55; color: #fff; padding: 20px; text-align: center; } header nav ul { list-style: none; display: flex; justify-content: center; gap: 16px; padding: 0; margin: 10px 0 0; flex-wrap: wrap; } header nav a { color: #fff; text-decoration: none; } main, aside, footer { max-width: 720px; margin: 0 auto; padding: 20px; } article { background: #fff; border: 1px solid #ddd; border-radius: 6px; padding: 16px; margin-bottom: 20px; } article img { max-width: 100%; height: auto; border-radius: 4px; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 8px 10px; text-align: left; } th { background: #2b3a55; color: #fff; } video { max-width: 100%; height: auto; border-radius: 6px; display: block; margin-top: 10px; } aside { background: #fff; border: 1px solid #ddd; border-radius: 6px; } aside ul { list-style: none; padding: 0; } aside li { margin-bottom: 8px; } footer { text-align: center; background: #2b3a55; color: #d7dce6; max-width: 100%; } </style></head><body>
<header> <h1>The Weekly Byte</h1> <nav> <ul> <li><a href="#featured">Featured</a></li> <li><a href="#recent">Recent Posts</a></li> <li><a href="#stats">Post Stats</a></li> </ul> </nav> </header>
<main> <article id="featured"> <header> <h2>Why Semantic HTML Still Matters in 2026</h2> <p>By Priya Nandan — <time datetime="2026-08-01">August 1, 2026</time></p> </header> <img src="https://placehold.co/640x320" alt="Illustration of HTML tags forming a webpage structure"> <p> Div-and-span soup still works, technically — browsers don't refuse to render it. But every div you swap for a header, article, or nav is a small gift to search engines, screen readers, and the next developer who opens this file. </p> </article>
<section id="recent"> <h2>Recent Posts</h2> <article> <h3>Flexbox vs. Grid: When to Reach for Which</h3> <p>By Rohan Mehta — <time datetime="2026-07-28">July 28, 2026</time></p> <p>A practical comparison of the two layout models, with real examples of each.</p> <a href="#">Read more →</a> </article> <article> <h3>A Beginner's Guide to ARIA Landmarks</h3> <p>By Asha Verma — <time datetime="2026-07-21">July 21, 2026</time></p> <p>How ARIA roles fill the gaps that native HTML elements don't cover.</p> <a href="#">Read more →</a> </article> <article> <h3>Speeding Up Page Loads With Lazy-Loaded Images</h3> <p>By Karan Singh — <time datetime="2026-07-14">July 14, 2026</time></p> <p>The loading="lazy" attribute, explained with before-and-after load times.</p> <a href="#">Read more →</a> </article> </section>
<section id="stats"> <h2>Post Stats</h2> <table> <thead> <tr> <th scope="col">Title</th> <th scope="col">Author</th> <th scope="col">Published</th> <th scope="col">Read Time</th> </tr> </thead> <tbody> <tr> <td>Why Semantic HTML Still Matters in 2026</td> <td>Priya Nandan</td> <td>Aug 1, 2026</td> <td>6 min</td> </tr> <tr> <td>Flexbox vs. Grid: When to Reach for Which</td> <td>Rohan Mehta</td> <td>Jul 28, 2026</td> <td>8 min</td> </tr> <tr> <td>A Beginner's Guide to ARIA Landmarks</td> <td>Asha Verma</td> <td>Jul 21, 2026</td> <td>5 min</td> </tr> </tbody> </table> </section>
<section id="video-highlight"> <h2>This Week's Highlight</h2> <video controls poster="https://placehold.co/640x360" width="640" height="360"> Your browser does not support embedded video. </video> </section> </main>
<aside> <h2>Categories</h2> <ul> <li><a href="#">HTML & CSS</a></li> <li><a href="#">JavaScript</a></li> <li><a href="#">Accessibility</a></li> <li><a href="#">Performance</a></li> </ul> </aside>
<footer> <p>© 2026 The Weekly Byte. All rights reserved.</p> </footer>
</body></html>Sample Run
Open blog.html in a browser, or use the live preview above, and try the following:
- Click "Recent Posts" or "Post Stats" in the header nav — both jump straight to that part of the page via fragment links, no JavaScript involved.
- Look at the Post Stats table — because it is marked up with real
<table>/<th>/<td>elements, a screen reader can announce "Read Time, column 4" for any cell, something a div-based grid cannot do without extra ARIA. - Click the video's play button — the browser's native controls (added by the
controlsattribute) handle play, pause, and volume without any extra markup. - Resize the window and notice the sidebar categories remain a clearly separate block from the blog posts — that is the
<aside>/<main>split doing its job.
Extend This Project
- Add pagination links ("Older Posts") at the bottom of the Recent Posts section using
<nav aria-label="Pagination">. - Turn each category in the sidebar into a link that would filter posts by that tag on a real backend.
- Add an RSS feed link in the footer using
<link rel="alternate" type="application/rss+xml">in the<head>. - Make the Post Stats table sortable by clicking column headers (a great first JavaScript project once you've finished the HTML courses).
- Add an
<audio>element withcontrolsfor a podcast-episode version of the featured post.
Summary
You structured a realistic blog homepage using the sectioning elements that match what each piece of content actually is: a header and footer for page-wide content, article elements for standalone posts, a real data table for tabular statistics, an aside for tangential content, and an embedded video for multimedia. Reaching for the right landmark instead of a generic div is what lets browsers, search engines, and assistive technology all understand this page the same way a human reader does.