Skip to content
All essays
WebJanuary 28, 202413 min

Web Accessibility WCAG Complete Guide

Master web accessibility with WCAG guidelines, ARIA attributes, and testing strategies for inclusive design

Ü
Ümit Uz
Mobile & Full Stack Developer

Accessibility isn't optional—it's essential. Let's master WCAG guidelines and create inclusive web experiences.

What is WCAG?

WCAG (Web Content Accessibility Guidelines) are standards for making web content accessible to people with disabilities.

WCAG 2.1 Principles (POUR)

  1. 1Perceivable: Users must perceive content
  2. 2Operable: Users must operate interface
  3. 3Understandable: Users must understand content
  4. 4Robust: Content must work with assistive tech

Level Conformance

  • A: Minimum accessibility
  • AA: Standard compliance (recommended)
  • AAA: Highest accessibility (difficult)

Perceivable

1. Text Alternatives

All images need alt text:

html
<!-- Decorative -->
<img src="decorative.png" alt="" role="presentation">

<!-- Informative -->
<img src="chart.png" alt="Bar chart showing 50% increase">

<!-- Complex -->
<img src="complex.png" alt="Detailed description">
<p class="sr-only">Full description in text</p>

2. Captions for Media

html
<video controls>
  <source src="video.mp4" type="video/mp4">
  <track kind="captions" src="captions.vtt" srclang="en" label="English">
</video>

3. Contrast Ratios

Minimum contrast requirements:

  • Normal text: 4.5:1
  • Large text (18pt+): 3:1
  • UI components: 3:1
css
/* Good contrast */
.text {
  color: #1a1a1a; /* Dark gray on white = 16.5:1 */
  background: #ffffff;
}

/* Bad contrast */
.text {
  color: #999999; /* Light gray on white = 2.8:1 */
  background: #ffffff;
}

Test with: WebAIM Contrast Checker

4. Resizable Text

css
/* Allow 200% zoom without breaking */
html {
  font-size: 100%; /* Base size */
}

body {
  /* Use relative units */
  font-size: 1rem;
  line-height: 1.5;
}

/* Avoid fixed widths */
.container {
  max-width: 1200px;
  width: 100%; /* Fluid */
}

Operable

1. Keyboard Accessible

All interactive elements must work with keyboard:

html
<!-- Bad: No keyboard access -->
<div onclick="doSomething()">Click me</div>

<!-- Good: Accessible -->
<button onclick="doSomething()">Click me</button>

<!-- Custom element with keyboard -->
<div
  role="button"
  tabindex="0"
  onkeydown="if (event.key === 'Enter') doSomething()"
  onclick="doSomething()"
>
  Click me
</div>

2. Focus Indicators

Visible focus for keyboard navigation:

css
/* Remove default outline */
*:focus {
  outline: none;
}

/* Add visible focus indicator */
*:focus-visible {
  outline: 3px solid #0066cc;
  outline-offset: 2px;
}

/* Skip to content link */
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #0066cc;
  color: white;
  padding: 8px;
  text-decoration: none;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}

3. Sufficient Time

Provide enough time to read and interact:

javascript
// Allow users to disable timeouts
const timeout = setTimeout(() => {
  // Auto-action
}, 5000);

// Provide disable option
const disableTimeout = checkbox.checked;
if (disableTimeout) {
  clearTimeout(timeout);
}

4. Seizure Prevention

Don't flash more than 3 times per second:

css
.animation {
  /* Avoid fast flashing */
  animation: flash 0.5s infinite; /* Bad! */
}

@keyframes flash {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

Understandable

1. Language Declaration

html
<html lang="en">
<head>
  <title>Page Title</title>
</head>
</html>

2. Consistent Navigation

Keep navigation consistent across pages:

html
<nav aria-label="Main">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>

3. Error Identification

Clear error messages:

html
<form>
  <label for="email">Email:</label>
  <input
    id="email"
    type="email"
    required
    aria-invalid="false"
    aria-describedby="email-error"
  >
  <span id="email-error" role="alert" class="error">
    Please enter a valid email address
  </span>
</form>

4. Instructions and Labels

html
<form>
  <fieldset>
    <legend>Choose your plan:</legend>

    <input id="basic" name="plan" type="radio" value="basic">
    <label for="basic">Basic Plan - $9/month</label>

    <input id="pro" name="plan" type="radio" value="pro">
    <label for="pro">Pro Plan - $19/month</label>
  </fieldset>
</form>

Robust

1. ARIA Attributes

Enhance accessibility with ARIA:

html
<!-- Landmarks -->
<header role="banner">
  <nav aria-label="Main">...</nav>
</header>

<main role="main">
  <article aria-labelledby="article-title">
    <h1 id="article-title">Article Title</h1>
  </article>
</main>

<aside aria-label="Sidebar">...</aside>

<footer role="contentinfo">...</footer>

<!-- Live regions -->
<div role="status" aria-live="polite">
  Form submitted successfully
</div>

<div role="alert" aria-live="assertive">
  Error occurred
</div>

<!-- Dynamic content -->
<div role="region" aria-live="polite" aria-atomic="true">
  Loading your data...
</div>

2. Semantic HTML

Use proper HTML elements:

html
<!-- Bad -->
<div class="button">Click me</div>
<div class="header">Title</div>
<div class="nav">Links</div>

<!-- Good -->
<button>Click me</button>
<h1>Title</h1>
<nav><a href="/">Link</a></nav>

Testing Accessibility

Automated Testing

Lighthouse:

bash
# Chrome DevTools
# Lighthouse > Accessibility

axe DevTools:

bash
# Chrome Extension
# Scan entire page

WAVE:

bash
# Browser extension
# Visual accessibility feedback

Manual Testing

Keyboard Navigation:

  1. 1Tab through entire page
  2. 2Verify focus order is logical
  3. 3All interactive elements reachable
  4. 4Focus indicators visible

Screen Reader:

  1. 1NVDA (Windows) - Free
  2. 2JAWS (Windows) - Paid
  3. 3VoiceOver (Mac) - Built-in
  4. 4TalkBack (Android) - Built-in

Color Contrast:

  1. 1Use WebAIM Contrast Checker
  2. 2Test with grayscale
  3. 3Test with color blindness simulators

Testing Checklist

  • [ ] All images have alt text
  • [ ] Color contrast meets WCAG AA
  • [ ] Keyboard navigation works
  • [ ] Focus indicators visible
  • [ ] Form fields have labels
  • [ ] Error messages clear
  • [ ] ARIA attributes correct
  • [ ] Semantic HTML used
  • [ ] Skip links provided
  • [ ] Captions on videos
  • [ ] Resizable to 200%
  • [ ] Works with screen reader

Common Mistakes

1. Missing Alt Text

html
<!-- Bad -->
<img src="photo.jpg">

<!-- Good -->
<img src="photo.jpg" alt="Sunset over mountains">

2. Poor Focus Styles

css
/* Bad */
*:focus {
  outline: none;
}

/* Good */
*:focus-visible {
  outline: 3px solid currentColor;
  outline-offset: 2px;
}

3. Insufficient Color Contrast

css
/* Bad */
.text {
  color: #cccccc; /* Too light */
  background: #ffffff;
}

/* Good */
.text {
  color: #333333; /* Sufficient contrast */
  background: #ffffff;
}

4. Missing Form Labels

html
<!-- Bad -->
<input type="email" placeholder="Email">

<!-- Good -->
<label for="email">Email:</label>
<input id="email" type="email">

Benefits of Accessibility

  1. 1Larger Audience: 15% of world population has disabilities
  2. 2Better SEO: Search engines favor accessible sites
  3. 3Legal Compliance: ADA, Section 508 requirements
  4. 4Better UX: Accessibility helps everyone
  5. 5Future-Proof: Aging population needs accessible sites

Conclusion

Accessibility is not optional—it's essential. Start with semantic HTML, ensure keyboard navigation, provide text alternatives, and test thoroughly. Use automated tools but don't rely on them—manual testing with assistive technologies is crucial.

Build for everyone, not just the average user. Accessibility makes the web better for all of us.

Related essays

Next essay
Frontend Debugging Tools and Techniques