CreaTech
← All posts
accessibilityfrontendweb-development

Accessibility is not optional

A practical baseline for accessible web development: the checks that catch 80% of issues before they reach a user who needs them.

Accessibility is one of those things that gets treated as a stretch goal, something to add at the end if there's time. There's rarely time. And the people who need it most are the ones who can't work around the gaps.

Here's the baseline I build into every project from the start.

Semantic HTML is 70% of the work

Most accessibility issues come from using the wrong element. A <div> with a click handler instead of a <button>. An image with no alt. A heading hierarchy that skips from <h1> to <h4>.

Semantic HTML gives browsers, screen readers, and search engines the right information for free. You don't need ARIA if the element already communicates what it is:

<!-- Wrong: requires ARIA to be accessible -->
<div role="button" tabindex="0" onClick={handleClick}>Submit</div>
 
<!-- Right: keyboard accessible, announces as a button, submits forms -->
<button type="submit">Submit</button>

Start with the right element. Add ARIA only when native HTML can't express what you need.

Keyboard navigation should work without a mouse

Tab through the page. Can you reach every interactive element? Does it have a visible focus indicator? Can you activate it with Enter or Space?

The default browser focus outline is fine. Don't remove it without replacing it:

/* Don't do this */
:focus { outline: none; }
 
/* Do this instead */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

:focus-visible only shows the outline for keyboard users, not mouse clicks. Best of both worlds.

It also gives you a free way to make hover effects keyboard-reachable: anything you write for :hover, write for :focus-visible too. Every experiment in the Lab does this, which is why you can tab to a demo and see the same thing a mouse user sees.

Hidden is not the same as hidden

There are several ways to take something off the screen, and they are not interchangeable. visibility: hidden and display: none remove an element from the accessibility tree as well as the page. The clipped-rectangle pattern removes it visually but leaves it announced.

That distinction bites in a specific way: if you hide an element's real text with visibility: hidden and mark its visible replacement aria-hidden, the element ends up with no accessible name at all. I walked into exactly that building the text scramble link, where the animation needs a visual layer that is not the real text. The fix is the clipped pattern:

/* Visually gone, still announced */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

Respect prefers-reduced-motion, and know when to cut rather than shorten

Most reduced-motion handling shortens durations. Sometimes that is wrong. For an effect built on rapid flicker, a slower version is not a kindness; it is the same problem with more time to notice it. Shorten transitions, but cut anything that flashes, scrambles, or parallaxes.

Colour contrast: the quick check

Text needs a contrast ratio of 4.5:1 against its background (3:1 for large text). This isn't a design constraint. It's the difference between readable and invisible for people with low vision. The Chrome DevTools accessibility panel checks this automatically. Run it.

Images need useful alt text

Not alt="image". Not alt="photo of product". Alt text describes what the image communicates:

<!-- Decorative image: empty alt, not missing -->
<img src="/divider.svg" alt="" />
 
<!-- Informative image -->
<img src="/team-photo.jpg" alt="The CreaTech team at a client workshop in London" />

An empty alt="" tells screen readers to skip the image. A missing alt attribute causes screen readers to announce the filename instead. Small distinction, big difference.

The WCAG audit that takes five minutes

Before shipping, I run four checks:

  1. Tab through every page with a keyboard only
  2. Run Lighthouse accessibility audit (score above 90 is a good signal, not a guarantee)
  3. Check colour contrast with the Chrome DevTools tool
  4. Test with macOS VoiceOver on at least the main user journey

This doesn't catch everything. But it catches the most common failures, and it costs less than an hour.

Accessibility isn't a feature you add later. It's the quality of the thing you built. If that matters to you, it matters to me too.

Got a project in mind?

I build fast, production-grade sites for freelance clients. Let’s talk.