Who you're designing for
About 1 in 4 adults has some form of disability. But accessibility isn't only permanent — it's also situational (in bright sun, holding a baby, noisy subway). Here's who your choices affect:
Blind / low vision
Uses screen readers (VoiceOver, NVDA, JAWS). Needs semantic HTML and alt text.
Color blindness
~8% of men, 0.5% of women. Don't rely on color alone to convey meaning.
Deaf / hard of hearing
Needs captions on videos, transcripts for audio, no audio-only instructions.
Motor impairments
May navigate with keyboard only, voice, or switch devices — no mouse.
Cognitive
Dyslexia, ADHD, low literacy, translation users. Clear language, predictable UI.
Situational
Small phone, glare, one hand on stroller, bad connection. Same solutions apply.
Use semantic HTML — the biggest win
Screen readers and keyboard users get 80% of their accessibility for free when you use the right elements. A <div> with onclick is invisible to a screen reader; a <button> is a button.
<div class="title">About us</div>
<div class="list"><div>...</div></div>
<h1>About us</h1>
<ul><li>...</li></ul>
- Headings: one
<h1>per page, then<h2>→<h3>in order - Landmarks:
<header>,<nav>,<main>,<footer>— screen readers skip between them - Lists:
<ul>/<ol>announce "list of N items" - Buttons vs links: buttons do things, links go somewhere
Alt text for images — the 30-second fix
Every <img> needs an alt attribute. It describes the image to people who can't see it, and shows as text if the image fails to load.
<!-- Meaningful image: describe it --> <img src="sunset.jpg" alt="Orange sunset over the Pacific"> <!-- Decorative image: empty alt (tells screen reader to skip it) --> <img src="divider.svg" alt=""> <!-- Image that IS the link text: describe the destination --> <a href="/cart"> <img src="cart.svg" alt="Shopping cart"> </a>
Color contrast — at least 4.5 : 1
WCAG AA requires 4.5:1 contrast for normal text and 3:1 for large text (18pt+). Light-gray-on-white links are the #1 accessibility sin on the web.
background: #fff;
background: #fff;
Test every color pair at WebAIM Contrast Checker. Chrome DevTools also shows contrast live when you pick a color.
Keyboard navigation — can you use your site without a mouse?
Try it: unplug your mouse, press Tab to move through your site, Enter/Space to activate, Esc to close modals. If you get stuck, so does every keyboard and screen-reader user.
- Visible focus: never remove
:focusoutlines without replacing them - Logical order: tab order should follow the visual reading order
- Skip link: let keyboard users skip repetitive nav — see below
- No focus traps: except inside modals (where you SHOULD trap focus)
<!-- Skip link: first element in the body --> <a href="#main" class="skip-link">Skip to main content</a> /* Hidden until focused */ .skip-link { position: absolute; left: -9999px; } .skip-link:focus { position: fixed; top: 10px; left: 10px; background: #111; color: #fff; padding: 8px 16px; }
Form labels — every input needs one
A placeholder is NOT a label. It disappears as soon as the user starts typing. Always pair inputs with <label>.
<input id="email" type="email">
- Group related radios with
<fieldset>+<legend> - Show inline errors with
aria-describedbyso screen readers announce them - Mark required fields with
requiredAND a visible asterisk
ARIA — only when semantic HTML isn't enough
The first rule of ARIA is: don't use ARIA. A real <button> beats role="button" every time. But when you must enhance a non-standard widget:
<!-- Tell screen readers what a custom icon button does --> <button aria-label="Close dialog">✕</button> <!-- Show/hide accessible state --> <button aria-expanded="false" aria-controls="menu">Menu</button> <!-- Announce dynamic updates (toast messages, live counters) --> <div role="status" aria-live="polite">5 items in cart</div>
Motion — respect prefers-reduced-motion
For users with vestibular disorders, large motion can cause nausea or migraines. Their OS has a setting to reduce motion — honor it.
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } }
Test by flipping the System Preferences → Accessibility → Display → "Reduce motion" on Mac.
Quick audit — three free tools
- WAVE — paste a URL and get a visual list of issues
- Chrome DevTools → Lighthouse — built in. Audit tab → Accessibility → Generate report
- axe DevTools — browser extension, most accurate automated checker
Automated tools catch about 40% of issues. The other 60% require manual testing — keyboard nav + screen reader.
Launch checklist
- Page has exactly one
<h1>, headings in order - All interactive elements are reachable by keyboard (Tab)
- Visible focus ring on every interactive element
- Every image has a meaningful or empty
alt - Text contrast passes 4.5:1 (3:1 for large text)
- Color isn't the only way meaning is conveyed
- Every form input has a
<label> - Error messages appear near the field + use
aria-describedby - Video has captions; audio has a transcript
prefers-reduced-motionrespected- Page works when zoomed to 200%
- Skip link present as the first focusable element
- Passes WAVE + Lighthouse audits with no critical issues
Go deeper
- WCAG 2.1 Quick Reference — the official standard, organized by task
- The A11y Project Checklist — community-maintained, beginner-friendly
- Inclusive Components — Heydon Pickering's deep-dive essays on specific UI patterns
- WebAIM Screen Reader guides — how to actually test with NVDA / JAWS / VoiceOver
- Microsoft Inclusive Design — the "mismatched interactions" framing that re-shaped the field
Accessibility is the baseline, not a feature.
Start with semantic HTML, label every input, respect motion preferences, and test with your keyboard. That covers 90% of real-world issues — everything else is polish on top of a solid foundation.