Accessibility in depth
What a screen reader actually announces, why landmarks and names carry the whole page, and how to test your own work in five minutes.
The page you do not see
Accessibility has a reputation for being a checklist bolted on at the end. It is really one idea: a page is a document with meaning, and that meaning has to survive being read by software instead of looked at with eyes.
Three visitors are worth keeping in mind. Someone using a screen reader hears the page, one element at a time. Someone using only a keyboard needs to reach every control, and always see which one is focused. Someone with low vision zooms to 200% or more. None of them is an edge case — they are reading the same page you are building, differently.
Landmarks: the map of the page
A screen reader can jump from region to region — but only if the page says where its regions are. Four elements do that job, and they cost nothing: <header> for the top of the page, <nav> for a set of navigation links, <main> for the content the page exists for, and <footer> for the end.
This is the structure lesson taken one step further. A <div class="header"> looks identical on screen and means nothing when it is read aloud. <header> looks exactly the same and announces itself as a landmark.
The four you will use constantly
header— the title, the mark, the navigation. A page usually has one at the top; a section can have its own.nav— one group of navigation links. A page can hold several, and each one should be recognisable from its links or itsaria-label.main— the part that is different on every page. Exactly one per page.footer— contact details, copyright, related links. The end of the page, or of a section.
A skeleton with landmarks
<body>
<header>
<p>Sourdough notes</p>
<nav aria-label="Main">
<a href="./index.html">Home</a>
<a href="./recipes.html">Recipes</a>
</nav>
</header>
<main>
<h1>Start your first starter</h1>
<p>Flour and water, and a week of patience.</p>
</main>
<footer>
<p>Written in a real kitchen.</p>
</footer>
</body>Give the page its landmarks
The structure below is built from divs and a paragraph. Replace the top region, the links, the main column and the closing line with the elements that mean what they say.
4 left to do
- The top region is a header element
- The links sit inside a nav element
- The content is inside a main element
- The closing line is a footer element
One element per region: <header>, <nav>, <main> and <footer> — no attributes needed.
Every control needs a name
A screen reader announces a text field as edit text, and then reads its name. A field whose only label is a placeholder is announced as edit text with nothing attached — the placeholder is treated as a hint, not a name, and it disappears the moment typing starts. A <label> connected to the field is what makes it announce "Email, edit text".
The same rule covers everything a visitor can operate. A button is announced by its text, so a button that shows only ">" is a button called "greater than". An image is announced by its alt, and a decorative image is marked with an empty alt="" so it is skipped rather than read out as a file name.
Give the fields their names
The form asks for an email and a message, but the fields are identified only by placeholders. Add a real label for each field, connected to it, and give the button words instead of a symbol.
2 left to do
- Each field has a label element
- Each label is connected with for
A label points at a field by id: <label for="email">Email</label> next to <input id="email">.
The name is computed
A control’s name can come from its <label>, its own text, an alt, or an aria-label. The browser chooses the first one that exists, so a button whose aria-label contradicts its visible words is a trap.
A role says what an element is; a state says what it is doing. HTML supplies both: <button> has a role, <details> reports whether it is open, a checkbox reports checked. Use ARIA only where HTML has no element for the job.
The tree the browser hands over
When the page is drawn, the browser also builds a second, smaller tree for assistive technology: the accessibility tree. Each node in it has a role, a name and sometimes a state, and most of those come straight from the element you chose. <button> supplies the role and its text supplies the name; <h2> supplies a heading at level two; aria-hidden="true" removes a node entirely. Nothing has to be duplicated for a screen reader — the markup is the source of the tree, which is why the element matters more than how it looks.
Test it in five minutes
You do not need special software to find the biggest problems. Put the mouse away and press Tab: every control should be reachable in a sensible order, and you should always see which one is focused. Zoom to 200% and check that nothing is cut off or overlapping. Then read the page out loud, in order, and ask of each control: could I tell what this does without seeing it?
When you want a fuller report, browser extensions like axe or Lighthouse list what is missing. They catch roughly the mechanical third — a missing alt, a label without a field. The other two thirds are choices only a person can judge, which is why the five-minute test above matters more.
Three mistakes a validator will not catch: an aria-label that contradicts the visible text; aria-hidden="true" on something a keyboard can still focus; and heading levels chosen for their size rather than their place in the outline.
Try these next
- Tab through the page and write down the name announced for each control.
- Give a button visible text and a stale
aria-label, and notice which one wins. - Change every heading to
<h2>and watch the outline stop describing the page.
Fix the structure first — headings, landmarks, labels. When the structure is right, the browser hands assistive technology almost everything for free.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
Which element should wrap the content the page exists for?
