Home HTML Intermediate Lesson 7 — Accessibility Basics

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):

PrincipleMeaningExample
PerceivableUsers can perceive all contentAlt text for images, captions for video
OperableUsers can operate all UIKeyboard navigation, no time limits
UnderstandableContent is clear and predictableClear labels, error messages, consistent navigation
RobustWorks with assistive technologiesValid 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>
First Rule of ARIA: Do not use ARIA if a native HTML element already provides the semantics. <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

CodeAccessibility 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 emojiHides the decorative emoji from screen readers — avoids "party popper emoji" being read aloud

6. Common Mistakes

Mistake 1 — Using divs as buttons

<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.

Mistake 2 — Removing focus outlines with CSS

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.

Mistake 3 — Low colour contrast text

Light grey text on white background fails WCAG contrast requirements. Test all text with a contrast checker before publishing.

Mistake 4 — Icon-only buttons without labels

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

Use semantic HTML first — it provides accessibility for free. ARIA is a supplement, not a replacement.
Test with keyboard only — unplug your mouse and try to use your site with Tab and Enter alone.
Check colour contrast — use the WebAIM Contrast Checker or browser DevTools.
Include a skip link on every page with navigation.
Install a screen reader — NVDA (Windows, free), VoiceOver (Mac/iOS, built-in), TalkBack (Android).
Run an automated audit — Chrome DevTools → Lighthouse → Accessibility section gives a score and actionable issues.

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:

  1. Add a skip link as the first element on the page
  2. Ensure every image has meaningful alt text
  3. Ensure every form input has a linked label
  4. Ensure every button has a descriptive accessible name
  5. 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.