Web Accessibility Fundamentals
Learn how to build websites that are accessible to everyone, including people with disabilities.
Web accessibility ensures that websites and applications are designed and developed so that people with disabilities can use them. It’s not just about serving a specific audience—it’s about creating better user experiences for everyone.
Why Accessibility Matters
- Ethical Responsibility: Everyone deserves equal access to information and functionality
- Legal Requirements: Many countries have laws requiring digital accessibility (e.g., ADA, Section 508, EAA)
- Business Benefits: Accessible sites reach more users and often rank better in search engines
- Better User Experience: Accessibility improvements help all users, not just those with disabilities
Accessibility is often abbreviated as “a11y” (11 letters between ‘a’ and ‘y’), similar to internationalization (i18n) and localization (l10n).
Understanding Disabilities
To build accessible sites, it helps to understand the different types of disabilities:
- Visual: Blindness, low vision, color blindness
- Auditory: Deafness, hard of hearing
- Motor: Limited fine motor control, slower movement, paralysis
- Cognitive: Learning disabilities, distractibility, inability to focus on large amounts of information
- Seizure: Photosensitive epilepsy triggered by flashing effects
The WCAG Guidelines
The Web Content Accessibility Guidelines (WCAG) are the international standard for accessibility. They’re organized around four principles, often referred to as POUR:
- Perceivable: Information must be presentable to users in ways they can perceive
- Operable: Interface components must be operable by all users
- Understandable: Information and operation must be understandable
- Robust: Content must be robust enough to work with current and future technologies
WCAG has three conformance levels: A (minimum), AA (standard), and AAA (enhanced). Most organizations aim for AA compliance.
Semantic HTML: The Foundation of Accessibility
The simplest and most effective way to improve accessibility is to use HTML elements according to their intended purpose:
<!-- Bad: Divs don't convey meaning -->
<div class="header">
<div class="title">My Website</div>
</div>
<div class="nav">
<div class="nav-item">Home</div>
</div>
<div class="main">
<div class="article">
<div class="article-title">Article Title</div>
<div class="content">Content goes here...</div>
</div>
</div>
<div class="footer">Footer content</div>
<!-- Good: Semantic HTML tells assistive technology what each element is -->
<header>
<h1>My Website</h1>
</header>
<nav>
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav>
<main>
<article>
<h2>Article Title</h2>
<p>Content goes here...</p>
</article>
</main>
<footer>Footer content</footer>
Key Semantic HTML Elements
Element | Purpose |
---|---|
<header> | Introductory content, typically containing headings |
<nav> | Section with navigation links |
<main> | Main content of the document |
<article> | Self-contained composition that can be distributed independently |
<section> | Standalone section that doesn’t have a more specific semantic element |
<aside> | Content tangentially related to the content around it |
<footer> | Footer for the nearest sectioning content or sectioning root element |
<h1> -<h6> | Headings, with <h1> being the most important |
<button> | Clickable button |
<a> | Hyperlink |
Proper Heading Structure
Headings (<h1>
through <h6>
) create a hierarchical outline of your page:
<h1>Website Title</h1>
<h2>Section Title</h2>
<p>Content under this section.</p>
<h3>Subsection Title</h3>
<p>Content under this subsection.</p>
<h2>Another Section Title</h2>
<p>More content here.</p>
Screen reader users often navigate by headings, so a proper hierarchy is crucial. Tools like the WAVE browser extension can visualize your heading structure.
Images and Accessibility
All images need alternative text that conveys the same information:
<!-- Informative image -->
<img src="chart.png" alt="Sales chart showing 20% growth in Q4" />
<!-- Decorative image - empty alt attribute so screen readers ignore it -->
<img src="decorative-divider.png" alt="" />
<!-- Or use CSS for purely decorative images -->
<div class="decorative-divider"></div>
Complex images like charts or diagrams may need more detailed descriptions:
<figure>
<img src="complex-chart.png" alt="Q4 Sales Performance Chart" />
<figcaption>
Chart showing Q4 sales performance across 5 regions, with North leading at
34% market share, followed by South (27%), East (22%), West (12%), and
Central (5%).
</figcaption>
</figure>
Keyboard Accessibility
Many users navigate using only their keyboard. Ensure all interactive elements are keyboard accessible:
- Tab Order: Interactive elements should be navigable in a logical order using the Tab key
- Focus Styles: All interactive elements should have a visible focus indicator
- Keyboard Traps: Users shouldn’t get stuck in any part of your interface
- Shortcuts: Use standard keyboard shortcuts where applicable
/* Always have visible focus styles */
:focus {
outline: 2px solid #4d90fe;
outline-offset: 2px;
}
/* If you remove outline, provide an alternative */
.custom-button:focus {
outline: none; /* Removed default outline */
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5); /* Custom focus indicator */
}
ARIA: When HTML Isn’t Enough
Accessible Rich Internet Applications (ARIA) attributes supplement HTML when native semantics aren’t sufficient. Use them sparingly and only when necessary:
<!-- Label elements that don't have visible text -->
<button aria-label="Close">×</button>
<!-- Describe the relationship between elements -->
<div id="emailHelp">Must be a valid email address</div>
<input type="email" aria-describedby="emailHelp" />
<!-- Indicate the current state -->
<button aria-expanded="false">Show Details</button>
<div hidden>These are the details that will be shown when expanded.</div>
Remember the first rule of ARIA: Don’t use ARIA if you can use a native HTML element with the semantics you need
Common ARIA Attributes
Attribute | Purpose | Example |
---|---|---|
aria-label | Provides a label for objects that don’t have visible text | <button aria-label="Close">X</button> |
aria-labelledby | Identifies element(s) that label the current element | <div id="heading">Name</div><input aria-labelledby="heading"> |
aria-describedby | Associates descriptive text with the object | <input aria-describedby="help-text"><div id="help-text">Enter your username</div> |
aria-expanded | Indicates if a control is expanded | <button aria-expanded="false">Show Menu</button> |
aria-hidden | Hides elements from assistive technology | <div aria-hidden="true">Decorative content</div> |
aria-live | Indicates an area will be updated dynamically | <div aria-live="polite">Status messages appear here</div> |
role | Changes the semantic meaning of an element | <div role="button" tabindex="0">Act like a button</div> |
Forms and Accessibility
Forms are crucial for interaction but often create accessibility barriers:
<!-- Bad: No labels, unclear purpose -->
<form>
<input type="text" placeholder="Enter name" />
<input type="email" placeholder="Enter email" />
<button type="submit">Submit</button>
</form>
<!-- Good: Properly labeled, described, and structured -->
<form>
<div>
<label for="name">Name</label>
<input id="name" type="text" aria-required="true" />
</div>
<div>
<label for="email">Email</label>
<input
id="email"
type="email"
aria-required="true"
aria-describedby="email-help"
/>
<p id="email-help">We'll never share your email with anyone else.</p>
</div>
<div>
<fieldset>
<legend>Subscription Options</legend>
<div>
<input type="radio" id="option1" name="subscription" />
<label for="option1">Monthly</label>
</div>
<div>
<input type="radio" id="option2" name="subscription" />
<label for="option2">Annual</label>
</div>
</fieldset>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
Error Handling
Accessible forms need clear error messages and instructions:
<form>
<div>
<label for="username">Username</label>
<input
id="username"
aria-describedby="username-error"
aria-invalid="true"
/>
<div id="username-error" role="alert" class="error">
Username must be at least 5 characters long
</div>
</div>
<!-- More form fields -->
</form>
Color and Contrast
Color should never be the only means of conveying information:
<!-- Bad: Color alone indicates required fields -->
<style>
.required {
color: red;
}
</style>
<label class="required">Name</label>
<!-- Good: Both color and symbol indicate required fields -->
<style>
.required {
color: red;
}
.required::after {
content: " *";
}
</style>
<label class="required">Name</label>
Text needs enough contrast against its background:
- WCAG AA requires a contrast ratio of at least 4.5:1 for normal text
- WCAG AA requires a contrast ratio of at least 3:1 for large text (18pt or 14pt bold)
- WCAG AAA requires a contrast ratio of at least 7:1 for normal text
Use tools like the WebAIM Contrast Checker to verify your color choices.
Responsive Design and Accessibility
Responsive design is inherently more accessible when done properly:
- Flexible layouts: Use relative units (%, em, rem) instead of fixed pixels
- Media queries: Adapt layouts for different screen sizes
- Viewport settings: Ensure proper scaling on mobile devices
- Touch targets: Make interactive elements at least 44x44px for mobile users
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
/* Base styles for all devices */
body {
font-size: 16px;
line-height: 1.5;
}
/* Larger text on bigger screens */
@media (min-width: 768px) {
body {
font-size: 18px;
}
}
/* Touch-friendly buttons */
button {
min-height: 44px;
min-width: 44px;
padding: 0.5rem 1rem;
}
</style>
Text Alternatives for Audio and Video
Audio and video content needs alternatives:
<!-- Video with captions and transcript -->
<video controls>
<source src="video.mp4" type="video/mp4" />
<track kind="captions" src="captions.vtt" srclang="en" label="English" />
Your browser does not support the video tag.
</video>
<details>
<summary>Video Transcript</summary>
<p>Full text transcript of the video goes here...</p>
</details>
<!-- Audio with transcript -->
<audio controls>
<source src="podcast.mp3" type="audio/mpeg" />
Your browser does not support the audio tag.
</audio>
<details>
<summary>Audio Transcript</summary>
<p>Full text transcript of the audio goes here...</p>
</details>
Tables and Accessibility
Tables should be used for tabular data only, with proper structure:
<table>
<caption>
Monthly Sales by Region
</caption>
<thead>
<tr>
<th scope="col">Region</th>
<th scope="col">January</th>
<th scope="col">February</th>
<th scope="col">March</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">North</th>
<td>$10,000</td>
<td>$12,000</td>
<td>$15,000</td>
</tr>
<tr>
<th scope="row">South</th>
<td>$8,000</td>
<td>$9,000</td>
<td>$10,000</td>
</tr>
</tbody>
</table>
Dynamic Content and ARIA Live Regions
For content that updates without a page refresh:
<!-- Polite announcement (doesn't interrupt) -->
<div aria-live="polite" role="status">
Your message has been sent successfully.
</div>
<!-- Assertive announcement (interrupts current task) -->
<div aria-live="assertive" role="alert">
Warning: Your session will expire in 2 minutes.
</div>
Testing for Accessibility
B[Automated Testing]B --> C[Manual Testing]
C --> D[Assistive Technology Testing]
D --> E[User Testing]
E --> F{Issues Found?}
F -->|Yes| G[Fix Issues]
G --> B
F -->|No| H[Continue Monitoring]
“ —>
-
Automated testing tools:
-
Keyboard testing:
- Navigate using only Tab, Shift+Tab, Enter, Space, Arrow keys
- Ensure all functionality is available without a mouse
-
Screen reader testing:
- NVDA or JAWS (Windows)
- VoiceOver (macOS/iOS)
- TalkBack (Android)
- Orca (Linux)
-
User testing:
- Include people with disabilities in your testing process
Accessibility Checklist
Use this basic checklist for your projects:
- Semantic HTML is used appropriately
- Heading structure is hierarchical (
h1
→h6
) - Images have appropriate alt text
- Color is not used as the only means of conveying information
- Text has sufficient color contrast
- Forms have proper labels and error handling
- Page is navigable by keyboard only
- Focus indicators are visible
- ARIA is used correctly and only when necessary
- Dynamic content changes are announced to screen readers
- Page works well when zoomed to 200%
- Audio/video content has text alternatives
Conclusion
Accessibility is not a feature or an enhancement—it’s a requirement for creating truly inclusive web experiences. By following these guidelines and incorporating accessibility into your development process from the beginning, you’ll create websites that work better for everyone.
Remember that perfect accessibility is an ongoing process, not a final state. Start with the basics, test regularly, and continually improve your work to make the web more accessible for all users.