Project: A Blog Article Page
Long form content done properly: article structure, a table of contents, figures, code blocks, an author footer and Article structured data.
-
HTML Basics
- What is HTML: The Structure Layer of Every Web Page
- HTML Document Structure: DOCTYPE, html, head and body
- Elements, Tags and Attributes: The Vocabulary of HTML
- HTML Comments: Notes That Ship With Your Code
- Block Level and Inline Elements
- Writing and Running Your First HTML Page
- How a Browser Turns Markup Into a Page
- Text and Formatting
- Links and Navigation
- Images and Media
- Lists
- Tables
-
Forms
- Form Structure: form, action and method
- Input Types: Text, Email, Number, Date and the Rest
- Labels: The Most Important Element in a Form
- Checkboxes, Radio Buttons and Grouping
- select, option, optgroup and datalist
- textarea, File Uploads and Hidden Fields
- Buttons: submit, reset and button
- Built In Form Validation
- GET or POST: What Happens When a Form Is Submitted
- Semantic HTML
- HTML5 Features
- Head and Metadata
- HTML with CSS
- HTML with JavaScript
- Accessibility
-
HTML SEO
- How Google Works: Crawling, Indexing and Ranking
- SEO Friendly HTML Structure
- Titles and Descriptions That Earn Clicks
- Headings and Content Structure for Search
- Internal Linking and Anchor Text
- robots.txt and XML Sitemaps
- Canonical URLs and Duplicate Content
- Structured Data and JSON-LD
- Image SEO
- Core Web Vitals and Mobile Friendliness
- DevTools and Debugging
- Editor Productivity
- HTML Best Practices
- HTML Projects
- Advanced Projects
- Practice and Exams
The brief
Build a single blog article page: readable, navigable, correctly structured, and eligible for a rich result.
Requirements
- A complete
articlewith a header, body and footer. - A table of contents linking to each section.
- Published and updated dates in
timeelements. - At least one figure with a caption, one blockquote with attribution, and one code block.
- An author block.
- Related articles at the end.
Articlestructured data.- Open Graph tags.
The head
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>How to Read a Bus Timetable - Riverside Journal</title>
<meta name="description" content="Every route in the city, how the columns work, and the two services worth waiting for.">
<link rel="canonical" href="https://example.org/journal/bus-timetable">
<meta property="og:type" content="article">
<meta property="og:title" content="How to Read a Bus Timetable">
<meta property="og:description" content="Every route in the city, and the two worth waiting for.">
<meta property="og:url" content="https://example.org/journal/bus-timetable">
<meta property="og:image" content="https://example.org/images/bus-og.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="article:published_time" content="2026-03-02T09:00:00+05:30">
<meta property="article:modified_time" content="2026-08-11T14:20:00+05:30">
<meta name="twitter:card" content="summary_large_image">
<link rel="stylesheet" href="/styles/article.css">
</head>The article
<main id="main-content" tabindex="-1">
<article>
<header>
<h1>How to read a bus timetable</h1>
<p class="standfirst">Every route in the city, and the two worth waiting for.</p>
<p class="byline">
By <a href="/people/meera-iyer" rel="author">Meera Iyer</a> ·
<time datetime="2026-03-02">2 March 2026</time> ·
Updated <time datetime="2026-08-11">11 August 2026</time> ·
7 minute read
</p>
</header>
<nav aria-labelledby="toc-heading" class="toc">
<h2 id="toc-heading">On this page</h2>
<ol>
<li><a href="#columns">How the columns work</a></li>
<li><a href="#symbols">The symbols nobody explains</a></li>
<li><a href="#night">Night services</a></li>
</ol>
</nav>
<h2 id="columns">How the columns work</h2>
<p>Each column is one journey, read top to bottom.</p>
<figure>
<img src="/images/timetable-1200.jpg"
srcset="/images/timetable-600.jpg 600w, /images/timetable-1200.jpg 1200w"
sizes="(max-width: 45rem) 100vw, 45rem"
alt="A printed timetable with one journey highlighted down a single column"
width="1200" height="800" loading="lazy">
<figcaption>One column, one journey. The rows are stops in order.</figcaption>
</figure>
<h2 id="symbols">The symbols nobody explains</h2>
<dl>
<div><dt>A hyphen</dt><dd>This journey does not call at this stop.</dd></div>
<div><dt>A letter</dt><dd>See the note at the foot of the column.</dd></div>
</dl>
<figure>
<blockquote cite="https://example.org/reports/transport-2026">
<p>Bus ridership recovered faster than any other mode, without any fare increase.</p>
</blockquote>
<figcaption>
District Transport Review, <cite>Annual Report 2026</cite>
</figcaption>
</figure>
<h2 id="night">Night services</h2>
<p>Night buses use a separate numbering scheme:</p>
<pre><code>Day routes: 12A, 27, 44
Night routes: N12, N27</code></pre>
<footer class="article-footer">
<h2>About the author</h2>
<p>
<img src="/images/meera.jpg" alt="" width="64" height="64" class="avatar">
Meera Iyer writes about how cities work.
<a href="/people/meera-iyer">More from Meera</a>.
</p>
<h2>Filed under</h2>
<ul class="tags">
<li><a href="/tags/transport">Transport</a></li>
<li><a href="/tags/cities">Cities</a></li>
</ul>
</footer>
</article>
<aside aria-labelledby="related-heading">
<h2 id="related-heading">Related reading</h2>
<ul>
<li><a href="/journal/metro-interchanges">Which interchanges are worth using</a></li>
<li><a href="/journal/fare-caps">How daily fare caps actually work</a></li>
</ul>
</aside>
</main>Decisions worth noting
| Decision | Reason |
|---|---|
Table of contents in a labelled nav | It is navigation, and there is more than one on the page |
| Ids on section headings | Deep links and the table of contents both need them |
Author avatar with alt="" | The name is beside it in text |
| Blockquote inside a figure | The attribution is not part of the quotation |
Related reading in an aside | Removing it would not damage the article |
Both dates in time | Machine readable for search and for structured data |
Reading comfort
article {
max-width: 42rem;
margin-inline: auto;
}
article p,
article li {
max-width: 65ch; /* comfortable line length */
line-height: 1.7;
}
article h2 {
margin-top: 2.5rem;
scroll-margin-top: 5rem; /* clears a sticky header on fragment links */
}
figure { margin-inline: 0; }
figure img { width: 100%; height: auto; border-radius: 8px; }
figcaption { font-size: 0.9rem; color: #475569; padding-top: 0.5rem; }
pre {
overflow-x: auto; /* long lines scroll inside the block */
padding: 1rem;
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 8px;
}
blockquote {
margin-inline: 0;
padding-left: 1.25rem;
border-left: 3px solid #1e3a8a;
font-size: 1.125rem;
}Structured data
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.org/" },
{ "@type": "ListItem", "position": 2, "name": "Journal", "item": "https://example.org/journal" }
]
},
{
"@type": "Article",
"headline": "How to read a bus timetable",
"description": "Every route in the city, and the two worth waiting for.",
"image": "https://example.org/images/bus-og.jpg",
"datePublished": "2026-03-02T09:00:00+05:30",
"dateModified": "2026-08-11T14:20:00+05:30",
"author": { "@id": "#meera" },
"publisher": {
"@type": "Organization",
"name": "Riverside Journal",
"logo": { "@type": "ImageObject", "url": "https://example.org/logo.png" }
},
"mainEntityOfPage": "https://example.org/journal/bus-timetable"
},
{
"@type": "Person",
"@id": "#meera",
"name": "Meera Iyer",
"url": "https://example.org/people/meera-iyer"
}
]
}
</script>Checking your work
- Validate.
- Follow every table of contents link; does the heading clear the sticky header?
- Read the headings alone. Do they describe the article?
- Test the Open Graph card in a platform debugger.
- Test the structured data.
- Check the code block scrolls inside itself at 320 pixels rather than widening the page.
Extensions
- Highlight the current section in the table of contents as the reader scrolls.
- Add previous and next article links.
- Add a reading progress indicator using
progress. - Add a print stylesheet.
- Add a comments section as nested
articleelements.
Practice
- Build the article page with your own content.
- Add the table of contents and confirm fragment links land correctly.
- Add
Articlestructured data and validate it. - Test the social preview card before sharing it anywhere.