Accessibility Basics
Build websites that everyone can use — including people with visual, auditory, motor, or cognitive disabilities.
1. Introduction
Web accessibility means making websites usable by people with disabilities. Around 1 in 5 people in the world has some form of disability. This includes:
- Visual disabilities — blindness, low vision, colour blindness
- Auditory disabilities — deafness, hard of hearing
- Motor disabilities — cannot use a mouse, tremors, limited mobility
- Cognitive disabilities — dyslexia, attention disorders, memory impairment
Accessibility is not just ethical — it is often a legal requirement (WCAG, ADA, EN 301 549) and it also improves the experience for all users.
2. Theory
WCAG — Web Content Accessibility Guidelines
WCAG is the international standard for web accessibility, organised around 4 principles (POUR):
| Principle | Meaning | Example |
|---|---|---|
| Perceivable | Users can perceive all content | Alt text for images, captions for video |
| Operable | Users can operate all UI | Keyboard navigation, no time limits |
| Understandable | Content is clear and predictable | Clear labels, error messages, consistent navigation |
| Robust | Works with assistive technologies | Valid HTML, ARIA attributes |
Keyboard Navigation
Many users navigate entirely by keyboard. Try it: press Tab to move forward through focusable elements on a page, Shift+Tab to move backward, Enter to activate links and buttons, Space to check checkboxes.
Every interactive element must be reachable by keyboard. Native HTML elements (<a>, <button>, <input>) are keyboard accessible by default. Custom elements need tabindex.
ARIA — Accessible Rich Internet Applications
ARIA attributes add semantic meaning when HTML alone is not enough:
<!-- Role -- what the element is -->
<div role="button" tabindex="0">Custom Button</div>
<!-- aria-label -- name when no visible label exists -->
<button aria-label="Close dialog">×</button>
<!-- aria-labelledby -- reference another element as the label -->
<section aria-labelledby="section-title">
<h2 id="section-title">About Us</h2>
</section>
<!-- aria-describedby -- reference an element for description -->
<input aria-describedby="password-hint">
<p id="password-hint">Must be at least 8 characters.</p>
<!-- aria-expanded -- indicates open/closed state -->
<button aria-expanded="false" aria-controls="menu">Menu</button>
<!-- aria-hidden -- hide from screen readers -->
<span aria-hidden="true">★</span> <span class="sr-only">5 stars</span>
<!-- aria-live -- announce dynamic content changes -->
<div aria-live="polite" id="status"></div>
<button> is always better than <div role="button">.
Focus Management
<!-- tabindex="0" -- add to tab order -->
<div tabindex="0">Focusable div</div>
<!-- tabindex="-1" -- focusable via JS but not tab order -->
<div tabindex="-1" id="modal">Modal content</div>
<!-- Never use tabindex > 0 -- it breaks natural tab order -->
Colour Contrast
Text must have sufficient contrast against its background. WCAG AA requires:
- Normal text: at least 4.5:1 contrast ratio
- Large text (18pt+ or 14pt bold): at least 3:1
- UI components and graphical objects: at least 3:1
Skip Links
A "Skip to main content" link at the top of the page lets keyboard users bypass the navigation:
<!-- First element on the page -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<!-- Usually visually hidden, shown on focus -->
<main id="main-content">
<!-- page content -->
</main>
Screen Reader Only Text
To add text visible only to screen readers (not displayed visually), use CSS to position it off-screen:
<!-- HTML -->
<span class="sr-only">Navigation menu</span>
<!-- CSS -->
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
3. Real World Example
When Apple's VoiceOver screen reader reads a webpage, it reads heading levels to create an outline, reads alt text for images, reads button labels to announce what they do, and reads form labels to describe input fields. A blind user navigating by keyboard depends entirely on proper HTML semantics and ARIA to use a website. Without them, the site is completely unusable for that person.
4. Code Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Accessible Page Example</title>
</head>
<body>
<!-- Skip link for keyboard users -->
<a href="#main" class="skip-link">Skip to main content</a>
<header>
<img src="logo.svg" alt="Acme Corp company logo">
<nav aria-label="Primary navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<!-- aria-current marks the active page -->
<li><a href="/services" aria-current="page">Services</a></li>
</ul>
</nav>
</header>
<main id="main">
<!-- Accessible form -->
<form novalidate>
<h1>Subscribe to Our Newsletter</h1>
<label for="sub-email">
Email Address <span aria-hidden="true">*</span>
<span class="sr-only">(required)</span>
</label>
<input
type="email"
id="sub-email"
name="email"
required
aria-required="true"
aria-describedby="email-error">
<span id="email-error" role="alert" aria-live="assertive"></span>
<!-- Icon-only button with accessible label -->
<button type="button" aria-label="Close subscription form">
× <!-- × symbol -->
</button>
<button type="submit">Subscribe</button>
</form>
<!-- Accessible image with detailed alt text -->
<figure>
<img
src="chart.png"
alt="Bar chart showing sales growth: Q1 £10k, Q2 £15k, Q3 £22k, Q4 £31k">
<figcaption>Figure 1: Quarterly sales performance 2024</figcaption>
</figure>
<!-- Decorative icon -- hidden from screen readers -->
<p>
<span aria-hidden="true">🎉</span>
Congratulations on completing this lesson!
</p>
</main>
</body>
</html>
5. Code Breakdown
| Code | Accessibility Purpose |
|---|---|
<a href="#main">Skip to main content</a> | Lets keyboard users jump past repeated nav to get to page content |
aria-label="Primary navigation" | Names the nav so screen readers distinguish it from other navs |
aria-current="page" | Announces the currently active page link to screen readers |
aria-required="true" | Tells screen readers this field is required (paired with the HTML required attribute) |
aria-describedby="email-error" | Associates the error message element with the input — screen reader reads both label and error |
role="alert" aria-live="assertive" | When error text is added, screen reader immediately announces it |
aria-label="Close subscription form" | Gives the × button a meaningful name — without it, screen readers just say "button" |
aria-hidden="true" on emoji | Hides the decorative emoji from screen readers — avoids "party popper emoji" being read aloud |
6. Common Mistakes
<div onclick="...">Click me</div> is not keyboard accessible — Tab cannot reach it, Enter will not activate it, screen readers do not know it is interactive. Use <button> always.
Many developers add :focus { outline: none; } to remove the visible focus ring because it looks ugly. This makes the site unusable for keyboard users. Instead, style the focus ring beautifully rather than removing it.
Light grey text on white background fails WCAG contrast requirements. Test all text with a contrast checker before publishing.
A close button with just × inside has no accessible name. Add aria-label="Close" or visually-hidden text so screen readers announce what the button does.
7. Best Practices
8. Practice Exercise
Open Chrome DevTools on your About Me page. Run a Lighthouse audit (Lighthouse tab → Generate report → check Accessibility score). Fix any issues it flags. Then:
- Add a skip link as the first element on the page
- Ensure every image has meaningful alt text
- Ensure every form input has a linked label
- Ensure every button has a descriptive accessible name
- Tab through the whole page — can you reach everything?
9. Assignment
Audit your registration form from the forms lesson for accessibility. Improve it by: adding aria-describedby to each input pointing to a helpful hint, adding aria-required to required fields, adding a skip link, ensuring the form can be completed entirely by keyboard, and achieving a Lighthouse Accessibility score of 90+.
10. Interview Questions
Q1: What is web accessibility and why is it important?
Answer: Web accessibility means designing and building websites that can be used by people with disabilities — visual, auditory, motor, or cognitive. It is important for ethical reasons (everyone deserves equal access), legal reasons (required by law in many countries, e.g. ADA in the US, EN 301 549 in Europe), business reasons (larger audience, better SEO, better UX for all users), and technical reasons (accessible code is generally cleaner and more maintainable).
Q2: What is ARIA and when should you use it?
Answer: ARIA (Accessible Rich Internet Applications) is a set of HTML attributes that add semantic meaning and state information to elements for assistive technologies. Use ARIA only when native HTML cannot provide the needed accessibility — for example, to label icon-only buttons, announce dynamic content changes, or describe custom widgets. The first rule of ARIA: if a native HTML element exists, use it instead.
Q3: What is the difference between aria-label and aria-labelledby?
Answer: Both provide accessible names. aria-label takes a direct string value: aria-label="Close dialog". aria-labelledby references another element's ID: aria-labelledby="dialog-title" where the element with id="dialog-title" contains the label text. Use aria-labelledby when a visible label already exists on the page — this avoids duplication.
Q4: What is the purpose of a skip link?
Answer: A skip link is the first focusable element on a page — a link that says "Skip to main content". It allows keyboard users (and screen reader users) to bypass the navigation and jump directly to the page's main content. Without it, keyboard users must tab through every navigation link on every page before reaching the content they came for.