Capstone project
Capstone: an article page for everyone
Lesson 20 of 20 · 30 min · Module 6: Fast pages and the capstone
Bring everything together in a real article page: keyboard friendly, readable, light and dark, responsive down to small phones, calm for people who prefer less motion, and clean on paper.
Start this lesson →Free. No installation: you write and run the code in your browser, and it is checked automatically.
By the end, you’ll be able to…
- Combine accessibility, theming and responsive layout in one page
- Check a page in several situations: keyboard, phone, dark mode, print
- Work in small, verified steps
The idea
The markup is provided. Your job is the finishing work that separates a page that works from a page that works for everyone. Build it in small steps and run the checks often.
/* Suggested order */
1. Skip link, landmarks and the current page
2. Theme variables, light and dark
3. Sticky header, readable article, responsive figure
4. Related cards grid
5. Focus, reduced motion and print
01Start with structure
The skip link, the main id, the navigation name and aria-current change no pixels for most visitors, yet they decide whether keyboard and screen reader users can use the page at all.
02Then the system of values
Defining the theme variables before anything else means every later rule can use them, and dark mode works automatically for each new part you add.
03Finally, the situations
Test the page as different people experience it: with only the keyboard, on a 390px screen, in dark mode, with reduced motion, and in print preview. Each check in this capstone corresponds to one of those situations.
Keyboard: Tab → skip link → header links → article
Phone: no sideways scrolling, one column of cards
Dark: variables switch, text stays readable
Print: header and related links hidden
Your project brief
• Skip link: give the first link the class
skip-link and href="#main", give main the id main, hide the link with position: absolute; top: -48px; left: 16px; and show it with .skip-link:focus-visible { top: 8px; };• Navigation: add
aria-label="Main" to nav and aria-current="page" to the Blog link;• Theme: on
:root define --bg: #ffffff; --text: #1f2a24; --surface: #f4f7ef; --accent: #2f6f4e; and color-scheme: light dark; inside @media (prefers-color-scheme: dark) use --bg: #141a16; --text: #e6efe4; --surface: #1f2822; --accent: #8fd18f;; give body background: var(--bg); color: var(--text); margin: 0;;• Header:
.site-header { position: sticky; top: 0; background: var(--bg); display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between; padding: 12px 16px; };• Article:
main { padding: 16px; } and .article { max-inline-size: 65ch; margin-inline: auto; };• Figure: give the image a meaningful alt text and
width="1200" height="675"; style .photo img { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; };• Related:
.related-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: 16px; } and .card { background: var(--surface); border-radius: 12px; padding: 16px; transition: transform 200ms ease; };• Focus:
a:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; };• Motion: inside
@media (prefers-reduced-motion: reduce), .card { transition: none; };• Print: inside
@media print, hide .site-header, .related and .skip-link.What the checks look for
- A skip link is the first element and points to #main
- main has the id main
- The skip link appears on keyboard focus
- The main navigation is named and marks the current page
- Light theme colours are defined on :root
- Dark theme colours apply when people prefer dark
- The page background uses the theme
- Cards use the surface colour
- The header sticks to the top
- The article keeps a readable line length
- The photo has alt text and reserved space
- The photo keeps a 16:9 shape
- Related cards stack on a phone
- Related cards sit side by side at 900px
- Links show a clear focus outline
- Reduced motion removes the card transition
- The header is hidden on paper
- Related articles are hidden on paper
- The header fits a phone screen
- The main content fits a phone screen
Take this with you
A page is finished when it works for everyone, not just on your screen.
Go a little further
Add a theme toggle: a button that sets data-theme="dark" on the html element with three lines of JavaScript, and a [data-theme="dark"] rule with the dark values.