Arkendia Classrooms
Lesson 17 of 21 · 20 min

Accessibility: a site everyone can use

A website is only useful if people can actually use it. Some visitors cannot see the screen, some cannot use a mouse, some have low vision, some cannot hear audio, and many simply have a bad screen in bright sunlight. Accessibility means building for all of them. Good news: you have already done much of it by writing proper HTML. In this lesson you will complete the picture: contrast, focus, keyboard navigation, alternative text, a few ARIA basics and respect for motion preferences.

Why accessibility matters

Disability is not a rare edge case. Permanent, temporary and situational limitations affect many people at some point: a broken arm, a noisy train, a glaring sun, a slow connection, aging eyes. An accessible site is easier for everyone, and it is often also better for search engines. In many countries, accessibility is also a legal requirement for certain organizations, so it is a good habit to acquire early.

The reference for web accessibility is the set of Web Content Accessibility Guidelines (WCAG) published by the W3C, and the W3C Web Accessibility Initiative (WAI) offers clear introductions and tutorials. The guidelines are organized around four principles: content must be perceivable, operable, understandable and robust.

Start with semantic HTML

The single most effective accessibility technique is the one you learned in chapter 2: use the right element for the job.

  • Use button for actions and a for navigation. A div styled as a button is not focusable, cannot be activated with the keyboard and is not announced as a button.
  • Use headings in a logical order, lists for lists, and landmarks (header, nav, main, footer).
  • Associate each form field with a label.
  • Set the lang attribute on html, and on any passage in another language: <span lang="fr">bonjour</span>.
  • Give each page a unique, descriptive title.

Color contrast

Text must contrast enough with its background. WCAG measures contrast as a ratio between 1:1 (no difference) and 21:1 (black on white). At the AA level, the common target is at least 4.5:1 for normal text and 3:1 for large text (roughly 24 pixels, or about 19 pixels in bold) and for the boundaries of interface components such as input borders and buttons.

You do not have to calculate by hand: free contrast checkers online and the color picker of your browser’s developer tools display the ratio and tell you whether it passes. Typical failures are light gray text on white, white text on a pale accent color, and text over a busy photograph.

Remember too that color must not be the only way to carry meaning. A link inside a paragraph should be underlined or otherwise distinguishable; an error in a form must be explained in words, not just painted red.

Focus: knowing where you are

People who use the keyboard (and many assistive devices) move through a page with the Tab key. The focus indicator shows which element is currently active. Browsers draw one by default, and removing it is among the worst accessibility mistakes:

/* Do not do this */
*:focus { outline: none; }

Instead, make it visible and attractive. The :focus-visible pseudo-class applies the style when focus should be shown (mainly for keyboard use), without bothering mouse users:

:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 3px;
}

Make sure the indicator contrasts with the background and is not clipped by an overflow: hidden parent.

Keyboard navigation

Put your mouse aside and use your site with the keyboard only: Tab to move forward, Shift + Tab to go back, Enter to follow a link or press a button, Space to tick a box. Check that:

  • every interactive element can be reached and activated;
  • the focus order follows the visual and logical order of the page;
  • you never get trapped in a component;
  • the focused element is always visible, and not hidden under a sticky header.

Avoid tabindex values greater than 0, which scramble the natural order. Use tabindex="0" only in rare cases, and tabindex="-1" to make something focusable by script, not by Tab.

Skip links

Keyboard users should not have to tab through the whole menu on every page. A skip link lets them jump straight to the main content. Place it as the first element in body:

<a class="skip-link" href="#main">Skip to main content</a>
...
<main id="main">...</main>
.skip-link {
  position: absolute;
  left: 0.5rem;
  top: -4rem;
  padding: 0.5rem 1rem;
  background: var(--color-surface);
  z-index: 100;
}
.skip-link:focus {
  top: 0.5rem;
}

The link stays off-screen until it receives focus, when it slides into view.

Text alternatives

You wrote alt attributes earlier. Refine the habit:

  • Informative images: describe what matters in context, in a short sentence.
  • Decorative images: alt="".
  • Images that are links: describe the destination or action, not the picture.
  • Complex images such as charts: give a short alt and explain the data in nearby text.
  • Audio and video: provide captions and, where relevant, a transcript.

Text that is in an image cannot be resized or read by screen readers, so avoid putting important text in images.

ARIA: handle with care

ARIA (Accessible Rich Internet Applications) is a set of attributes that add accessibility information, mostly for complex custom widgets. The first rule of ARIA, which is reflected in the W3C guidance, says in essence: if a native HTML element does the job, use it instead of ARIA. No ARIA is better than bad ARIA, because a wrong ARIA attribute actively misleads assistive technologies.

A few safe and useful attributes for a simple site:

<nav aria-label="Main">...</nav>
<a href="index.html" aria-current="page">Home</a>
<button type="button" aria-label="Close the menu">X</button>
<svg aria-hidden="true">...</svg>
  • aria-label gives an accessible name when there is no visible text, and distinguishes several landmarks of the same type.
  • aria-current="page" marks the link to the page you are on in a menu.
  • aria-hidden="true" hides purely decorative content from assistive technologies. Never use it on focusable elements.

Warning. Do not add role or aria-* attributes you do not fully understand. For instance, role="button" on a div only changes the announcement, not the behavior: you would still have to add keyboard handling with JavaScript. A real button element gives you all of it for free.

Forms and errors

You built your contact form with labels. To improve it further: keep labels visible, explain constraints in text before the field, group related options in a fieldset, use the right type and autocomplete, and describe errors in words. You can link help text to a field with aria-describedby:

<label for="c-message">Your message</label>
<textarea id="c-message" name="message" aria-describedby="message-help"></textarea>
<p id="message-help">At least 10 characters.</p>

Text size and zoom

Use relative units so that text can scale, and let layouts reflow when visitors zoom. Never disable zoom in the viewport tag. Check your pages at 200% zoom: the content should remain usable without horizontal scrolling for ordinary text.

Respecting motion and preferences

As covered in the previous chapter, honor the reduced motion preference. In the same spirit, avoid autoplaying media, avoid flashing content, and consider offering readable defaults, such as sufficient line spacing, which help people with dyslexia and many others.

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

How to test accessibility

  1. Keyboard only: complete every task on your site without the mouse.
  2. Zoom and resize: enlarge text and zoom to 200%.
  3. Contrast: check text and interface colors with a checker.
  4. Automated tools: the developer tools of some browsers and free extensions can flag common issues. They catch only part of the problems, so they complement manual testing.
  5. Screen reader: try the one built into your system for a few minutes. Hearing your page read aloud is highly instructive.

Tip. Make accessibility part of your normal workflow from the start, not a final audit. It is much cheaper to choose the right element and a good color pair at the beginning than to repair a finished site.

Your turn

  1. Add a skip link to every page, pointing to the main element.
  2. Check that your focus indicators are visible, and define a :focus-visible style.
  3. Navigate your whole site by keyboard and note any problem.
  4. Check the contrast of your main text, link and button colors with a contrast checker; adjust any that fall below the targets.
  5. Review every alt attribute and make sure each one is useful, empty if decorative.
  6. Mark the current page link in your menu with aria-current="page" and style it.
See a solution
<body>
  <a class="skip-link" href="#main">Skip to main content</a>
  <header>...</header>
  <main id="main">...</main>
</body>
:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 3px;
}
a[aria-current="page"] {
  font-weight: 700;
  text-decoration: underline;
}

When you press Tab for the first time on a page, the skip link should appear. If a color pair fails the contrast target, darken the text or lighten the background until the checker passes, and update your CSS variable so that the whole site benefits.

Key takeaways

  • Semantic HTML (buttons, links, headings, labels, landmarks, lang) gives most of the accessibility you need.
  • Aim for contrast of at least 4.5:1 for normal text and 3:1 for large text and interface boundaries; never rely on color alone.
  • Never remove focus outlines; use :focus-visible to style them. Test with the keyboard and provide a skip link.
  • Write useful alt text, and alt="" for decorative images; provide captions for video.
  • Use ARIA sparingly: native HTML first, because no ARIA is better than bad ARIA. Respect prefers-reduced-motion.
Advertisement
Log in to save your progress. Log in