Lesson 02 · Part 1 · The document

Structuring documents

Every component sits on a page, and the page is a document. Three tiny settings decide whether that document works for everyone: the language, the title, and whether zoom is allowed. They are accessibility, not boilerplate.

In one minute

In plain words

Think of a book. The cover title tells you which book it is, the language on the spine tells you if you can read it, and the pages are printed in an order that makes sense. The browser needs the same three things before it can hand your page to a person using a screen reader or a magnifier.

1. Set the language, and mark the exceptions

Put a BCP 47 language tag on <html lang>. A screen reader is software that reads the page aloud. It uses lang to pick a voice. With the wrong language it reads words with the wrong accent, or spells them out. A German sentence on an English page gets lang="de" on that element only. This is WCAG 3.1.1 (page language) and 3.1.2 (parts).

Step 1. Choose how the markup is written for the sentence below.


          

2. Name the document with the title

The <title> is the label of the browser tab, and often the first thing a screen reader says when a page loads. Put the specific page first and the site second: "Checkout · Northwind". A single title of "Home" or "App" on every route is a bug (WCAG 2.4.2 Page Titled).

Step 1. Type a title for the checkout page.

Single-page apps change the page without a reload, so they must update document.title on every route change, or users never hear that the page changed. Lesson 08 covers moving focus too.

3. Viewport: let people zoom

The viewport meta tag tells phones how wide the page is. Two common values switch zoom off: user-scalable=no and maximum-scale=1. People with low vision rely on pinch zoom and browser zoom. Blocking it fails WCAG 1.4.4 (Resize Text) and 1.4.10 (Reflow). Try to enlarge the text below.

Step 1. Choose the viewport tag, then press Zoom in.


          
100%

Delivery slots open at 9:00. Choose one before 17:00.

The standard safe tag is <meta name="viewport" content="width=device-width, initial-scale=1">.

4. Source order is reading order

The accessibility tree (the simplified copy of the page that assistive technology reads) follows the source order, not the order you painted with CSS. The Tab key does too. If you reverse items visually with flex-direction: row-reverse or order, keyboard focus jumps around the screen (WCAG 1.3.2 Meaningful Sequence, 2.4.3 Focus Order).

Step 1. Choose the layout, click into the row, then press Tab through the buttons.

Focus order: (press Tab)

Reordering is fine when the order still makes sense. Fix it in the HTML, not with a positive tabindex, which creates a second, hidden order.

5. Put real content in the first HTML

A client-only app can send an empty <body> and build everything with JavaScript. If the script is slow, fails, or the user has a simple reader mode, there is nothing to read. If you must hydrate, send the primary text in the first response.

Step 1. Pick what the server sends, and imagine the script has not run.


          

Common mistakes

You seeWhy it is a problemFix
No lang, or lang="en" on a German pageWrong voice and pronunciation.Correct lang on html and on foreign passages.
<title>App</title> on every routeTabs and history are indistinguishable.Specific title first, site name second.
user-scalable=noLow vision users cannot zoom.Remove it and maximum-scale.
Empty body until JS runsNothing to read if scripts fail.Render primary text on the server.
CSS reorders focusable itemsFocus jumps around the screen.Change the HTML order instead.
Try it yourself
  1. View source on this page. Confirm lang, a unique title, and a viewport that does not disable zoom.
  2. Disable JavaScript in devtools and reload a site you build. Is the main content still there?
  3. Open five tabs of your app. Can you tell them apart by title alone?

Remember

Edit this example in the playground

'; $("l5-sr").textContent = '"Blank" (until app.js loads and runs)'; setVerdict($("l5-verdict"), "is-bad", "✕", "If the script is slow or fails, there is nothing to read."); } else { $("l5-code").textContent = '\n
\n

Checkout

Review your order...

\n
\n