Skip to main content

    Lesson 15 • Expert Track

    Web Accessibility (A11y)

    By the end of this lesson you'll be able to build pages that work for keyboard users, screen-reader users, and people with low vision — and you'll be able to spot and fix inaccessible markup on sight.

    What You'll Learn

    Use semantic HTML so screen readers and search engines understand your page
    Write alt text that describes images (and know when to leave it empty)
    Order headings h1–h6 logically so the page outline makes sense
    Make every control keyboard-operable with a visible focus ring
    Hit WCAG AA colour-contrast ratios so text stays readable
    Label form controls and add a skip link for screen-reader users
    Before this lesson: you should be comfortable writing basic HTML elements and forms, and styling them with CSS. If headings, links, and <label> feel new, review CSS Basics & Selectors first.

    💡 Think of It Like This

    Accessibility is like a building with ramps, lifts, and braille signs. A staircase works fine if you can walk — but a ramp lets everyone in, including the person in a wheelchair, the parent with a pushchair, and the courier with a heavy trolley.

    Your webpage is the building. A screen reader is a blind visitor who can only "see" the page through the labels and structure you provide. If your "button" is really a styled <div>, it's like a door with no handle — some visitors simply can't open it. Over 1 billion people worldwide live with a disability, so these ramps are not an edge case.

    1. Why Accessibility Matters

    Accessibility (often shortened to a11y — "a", then 11 letters, then "y") means building pages that work for people who use assistive technology: screen readers, keyboard-only navigation, screen magnifiers, and more. It is not a nice-to-have bolted on at the end; it is part of writing correct HTML.

    ReasonWhy you should care
    🧑‍🤝‍🧑 EthicalAround 15% of the world lives with a disability. The web should work for them too.
    ⚖️ LegalMany countries require WCAG compliance (ADA in the US, EAA in the EU). Lawsuits are real.
    📈 SEOSemantic HTML and alt text are exactly what search engines read to rank you.
    👥 UXAccessible sites are clearer and faster for everyone, not just disabled users.

    2. Semantic HTML — The Foundation

    The single most important thing for accessibility is to use the right HTML element for the job. A screen reader knows that <button> is clickable, that <nav> is navigation, and that <main> is the main content — but a <div> is meaningless furniture it has to skip past. "Semantic" just means the tag describes what the thing is, not how it looks.

    ❌ Inaccessible✅ Accessible
    <div onclick="..."><button>
    <div class="nav"><nav>
    <div class="header"><header>
    <b>Title</b><h1>Title</h1>

    Run the worked example below. The same visual layout is built twice — once from <div>s and once from real elements. They look identical, but only the second one tells a screen reader what each part is.

    Worked example: inaccessible vs accessible markup

    Same look, very different experience for a screen reader

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Semantic HTML</title>
      <style>
        body { font-family: system-ui, sans-serif; background:#0f172a; color:#e5e7eb; padding:20px; }
        .panel { background:#1e293b; border-radius:10px; padding:16px; margin:14px 0; }
        .fake-btn, .real-btn {
          display:inline-block; background:#3b82f6; color:white;
          padding:10px 18px; border-radius:8px; border:none;
          font:inherit; cursor:pointer; margin-top:8px;
        }
        h2 { 
    ...

    3. Heading Order & Alt Text

    Screen-reader users often jump heading to heading to scan a page, the way a sighted reader skims bold titles. That only works if your headings form a logical outline: one <h1> per page, then <h2> for each section, then <h3> under those. Never skip a level just to get a smaller font — that's a job for CSS, not for picking the wrong tag.

    For images, the alt attribute is the text a screen reader speaks in place of the picture. Get it right by image type:

    Image typeRuleExample
    InformativeDescribe what it showsalt="Golden retriever catching a ball"
    DecorativeEmpty alt (present, not missing!)alt=""
    Functional (logo/icon link)Describe the action/destinationalt="Acme home page"

    Worked example: heading order and alt text

    A correct outline plus the three kinds of alt text

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Headings & alt text</title>
      <style>
        body { font-family: system-ui, sans-serif; background:#0f172a; color:#e5e7eb; padding:20px; }
        img { border-radius:8px; background:#334155; }
        h1 { color:#3b82f6; }
        h2 { color:#22c55e; }
        h3 { color:#f59e0b; }
      </style>
    </head>
    <body>
    
      <!-- One h1 = the page title. Screen reader: "heading level 1". -->
      <h1>Dog Breeds</h1>
    
      <!-- h2 = a section under the h1. Outli
    ...

    4. Keyboard Navigation & Visible Focus

    Many people never touch a mouse. They move through a page with Tab (next control), Shift+Tab (previous), Enter/Space (activate), and Escape (close). For this to work, every interactive element must be reachable and must show a visible focus indicator — the ring that tells you where you are. Native elements (<a>, <button>, <input>) are focusable for free; that's another reason to use them.

    /* ✅ A clear focus ring for keyboard users */ :focus-visible { outline: 3px solid #3b82f6; /* high-contrast, easy to spot */ outline-offset: 2px; } /* ❌ NEVER remove the outline with no replacement */ /* :focus { outline: none; } <- keyboard users are now lost */

    The demo below is a full accessible page: a skip link, semantic landmarks, a labelled form, and a bright focus ring. Open it and press Tab repeatedly — watch the skip link appear first, then the focus ring jump from control to control.

    Worked example: a fully accessible page

    Skip link, landmarks, labels, and visible focus — press Tab to explore

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Accessible Page</title>
      <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { font-family: system-ui, sans-serif; background:#0f172a; color:#e5e7eb; }
    
        /* Skip link: hidden off-screen until it receives focus, then slides in. */
        .skip-link {
          position:absolute; top:-60px; left:10px; z-index:100;
          background:#3b
    ...

    5. Colour Contrast (WCAG AA)

    Low-contrast text — pale grey on white, light blue on teal — is hard to read for everyone and impossible for many people with low vision. WCAG sets a measurable target called a contrast ratio, from 1:1 (invisible) to 21:1 (black on white). To pass AA, the level most laws require, hit these numbers:

    LevelNormal textLarge text (18pt+/24px)
    AA (required)4.5:13:1
    AAA (best practice)7:14.5:1

    💡 Pro tip: Don't guess. Open browser DevTools, inspect a text element, and the colour picker shows the live contrast ratio with a pass/fail tick against AA and AAA.

    And never rely on colour alone to convey meaning — a red/green status dot is invisible to colour-blind users. Add an icon, a word, or a shape as well.

    🎯 Your Turn #1 — Fix the fake button

    This "card" uses a <div> as a button and an image with no alt text. Replace the blanks so it becomes accessible, then run it and check the expected screen-reader behaviour written in the comments.

    Your Turn #1: make the control real

    Swap the div-button for a <button> and give the image alt text

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Your Turn 1</title>
      <style>
        body { font-family: system-ui, sans-serif; background:#0f172a; color:#e5e7eb; padding:20px; }
        .card { background:#1e293b; border-radius:10px; padding:16px; max-width:340px; }
        .buy {
          display:inline-block; background:#22c55e; color:#0f172a;
          padding:10px 18px; border-radius:8px; border:none;
          font:inherit; font-weight:700; cursor:pointer; margin-top:10px;
        }
        :f
    ...

    🎯 Your Turn #2 — Label the form

    These inputs only have placeholder text — which vanishes when you type and is not a label. Connect each input to a <label> using matching for / id values, then verify the expected screen-reader behaviour in the comments.

    Your Turn #2: connect labels to inputs

    Add for/id so the screen reader announces each field's name

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Your Turn 2</title>
      <style>
        body { font-family: system-ui, sans-serif; background:#0f172a; color:#e5e7eb; padding:20px; }
        label { display:block; margin:12px 0 4px; color:#cbd5e1; font-size:14px; }
        input { width:100%; max-width:320px; padding:10px; border-radius:6px;
                border:2px solid #334155; background:#1e293b; color:white; }
        :focus-visible { outline:3px solid #3b82f6; outline-offset:2px; }
      
    ...

    🧩 Mini-Challenge — Build an accessible mini-page

    Support is faded now — only an outline is given. Build a small page from scratch that ties the whole lesson together. Use the worked page in section 4 as your reference if you get stuck.

    Mini-Challenge: accessible from scratch

    Skip link, landmarks, one labelled input, a real button, a visible focus ring

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Mini-Challenge</title>
      <style>
        body { font-family: system-ui, sans-serif; background:#0f172a; color:#e5e7eb; padding:20px; }
        /* 🧩 add a :focus-visible rule with a 3px outline */
      </style>
    </head>
    <body>
    
      <!-- 🧩 MINI-CHALLENGE: build a tiny but fully accessible newsletter page
           1. First link on the page = a skip link pointing to #main
           2. A <header> with an <h1> title and a <nav aria-label="Main">
    ...

    ⚠️ Common Errors (and the fix)

    • Missing alt text. Screen reader reads the file name out loud: "headphones-final-v2.png". Fix: add alt="..." describing the image, or alt="" if it's purely decorative.
    • Div-buttons. <div onclick="..."> can't be reached by Tab, doesn't respond to Enter/Space, and isn't announced as a button. Fix: use <button> (or <a> if it navigates).
    • Low contrast. Pale grey text on white reads at ~1.6:1 and fails WCAG AA. Fix: darken the text (or lighten the background) until DevTools shows at least 4.5:1 for normal text.
    • No labels. Inputs with only placeholder text are announced as an unnamed "edit text". Fix: add a <label> with for matching the input's id.
    • outline: none. Removing the focus ring with no replacement leaves keyboard users unable to see where they are. Fix: style :focus-visible with a high-contrast outline instead.

    📋 Quick Reference

    GoalUse this
    A clickable action<button>…</button>
    Navigation region<nav aria-label="Main">
    Main content landmark<main id="main">
    Informative image<img src="…" alt="what it shows">
    Decorative image<img src="…" alt="">
    Labelled input<label for="x">…</label><input id="x">
    Skip link<a href="#main">Skip to main content</a>
    Visible focus ring:focus-visible { outline: 3px solid #3b82f6 }
    Contrast (AA, normal text)at least 4.5:1

    ❓ Frequently Asked Questions

    What is the single most important thing I can do for accessibility?

    Use semantic HTML. Choosing the right element for the job — <button> for actions, <nav> for navigation, <h1>–<h6> for headings, <main> for the main content — gives screen readers, keyboards, and search engines built-in meaning for free. Most accessibility problems come from <div> and <span> used where a real element belongs.

    What does WCAG AA mean and which contrast ratio do I need?

    WCAG (Web Content Accessibility Guidelines) defines levels A, AA, and AAA. AA is the level most laws require. For AA, normal text needs a contrast ratio of at least 4.5:1 against its background, and large text (18pt/24px, or 14pt/18.66px bold) needs at least 3:1.

    Is it ever OK to write outline: none on focus?

    Only if you immediately provide a clearly visible replacement focus style. Removing the outline with nothing in its place makes the page impossible to use with a keyboard, because the user can no longer see where they are. The safe pattern is to style :focus-visible with a high-contrast outline instead.

    When should an image have an empty alt attribute (alt="")?

    Use alt="" for purely decorative images that add no information — background flourishes, spacer images, icons sitting next to text that already says the same thing. The empty alt tells the screen reader to skip the image. This is different from leaving alt off entirely, which makes the screen reader announce the file name, which is a real bug.

    How do I connect a label to a form input?

    Give the input an id and point a <label> at it with a matching for attribute: <label for="email">Email</label><input id="email">. The screen reader then announces the label when the field is focused, and clicking the label focuses the input. Placeholder text is not a label and disappears as soon as the user types.

    What is a skip link and why do I need one?

    A skip link is the first focusable link on the page ("Skip to main content") that jumps past the repeated header and navigation straight to <main>. Keyboard and screen-reader users would otherwise have to Tab through every nav link on every page. It is usually hidden until it receives focus.

    🎉 Lesson Complete

    You can now build pages that work for everyone. The essentials:

    • ✅ Reach for semantic HTML first — it's the #1 accessibility win
    • ✅ Give images real alt text (or alt="" when decorative)
    • ✅ Keep headings in order — one h1, then h2, then h3
    • ✅ Make every control keyboard-operable with a visible focus ring
    • ✅ Meet WCAG AA contrast — 4.5:1 for normal text
    • Label every form control and add a skip link

    Next up: HTML5 Semantic Architecture, where you'll structure whole pages with these landmark elements.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service