🦊 Web Accessibility Best Practices
Practical tips to make your site inclusive for everyone.
In this guide
1. HTML Semantics: Build a Strong Foundation
Using correct HTML elements is the first step to accessibility. Semantic HTML gives structure and meaning to your content, helping assistive technologies like screen readers understand it.
1.1 Use Semantic Structural Elements
Replace generic <div> and <span> with tags that
describe the content: <header>, <nav>,
<main>, <article>,
<section>, <aside>,
<footer>.
✅ Good
<header>
<h1>Site Title</h1>
<nav>...</nav>
</header>
<main>
<article>
<h2>Article</h2>
<p>Content...</p>
</article>
</main>
<footer>...</footer>
❌ Bad
<div class="header">...</div>
<div class="main">
<div class="article">
<div class="title">Article</div>
<p>...</p>
</div>
</div>
<div class="footer">...</div>
Screen readers provide shortcuts to jump between these landmarks, making navigation much faster.
1.2 Maintain a Correct Heading Hierarchy
Headings (<h1> to <h6>) should form a logical
outline. There should be only one <h1> per page, and you
shouldn't skip levels.
✅ Good
<h1>Main Title</h1>
<h2>Section 1</h2>
<h3>Subsection 1.1</h3>
<h2>Section 2</h2>
❌ Bad
<h1>Main</h1>
<h3>Oops, skipped h2</h3>
<h4>Another</h4>
1.3 Always Provide Alternative Text for Images
Every <img> must have an alt attribute describing its
content and function. Use empty alt="" for decorative images.
✅ Good
<img src="chart.png" alt="Bar chart showing sales growth of 20% in Q1 2026.">
<img src="decoration.png" alt="">
❌ Bad
<img src="chart.png" alt="chart">
<img src="decoration.png"> <!-- missing alt -->
1.4 Label Form Controls Properly
Every form input needs a <label> linked via for and
id. Use <fieldset> and <legend>
to group related controls.
✅ Good
<label for="name">Name:</label>
<input type="text" id="name">
<fieldset>
<legend>Choose option</legend>
<input type="radio" id="opt1">
<label for="opt1">Option 1</label>
</fieldset>
❌ Bad
<input type="text" placeholder="Name"> <!-- no label -->
<input type="radio"> Option 1
1.5 Use Tables for Tabular Data
When presenting data tables, use <caption>,
<th> with scope, and proper structure.
<table>
<caption>Monthly sales by product</caption>
<thead>
<tr><th scope="col">Product</th><th scope="col">January</th></tr>
</thead>
<tbody>
<tr><th scope="row">Product A</th><td>$100</td></tr>
</tbody>
</table>
2. VoiceOver & Screen Readers
Screen readers like VoiceOver (built into macOS and iOS) are essential tools for people with visual impairments. Testing with a screen reader helps you understand how your content is perceived by users who can't see the screen.
2.1 How to Enable VoiceOver
🖥️ On macOS:
- Press Cmd + F5 to turn VoiceOver on/off.
- Or go to System Settings → Accessibility → VoiceOver.
- Use the VoiceOver Utility to customize verbosity and navigation.
📱 On iOS:
- Go to Settings → Accessibility → VoiceOver and toggle it on.
- Or use Siri: "Turn on VoiceOver".
- Practice gestures: single tap to select, double tap to activate, three-finger swipe to scroll.
2.2 Basic VoiceOver Navigation
Once enabled, VoiceOver reads elements in order. Use these commands to navigate efficiently:
| Action | macOS | iOS |
|---|---|---|
| Move to next element | Ctrl + Option + → | Swipe right |
| Move to previous element | Ctrl + Option + ← | Swipe left |
| Activate a link/button | Ctrl + Option + Space | Double tap |
| Read from current position | Ctrl + Option + A | Two-finger swipe down |
| Open rotor (quick navigation) | Ctrl + Option + U | Rotate two fingers |
2.3 Testing Your Site with VoiceOver
Follow this simple checklist when testing:
- Navigate by headings: Use the rotor (Ctrl + Option + U on macOS) to jump between headings. Ensure the order is logical and there are no gaps.
- Check images: VoiceOver should read meaningful alt text for
informative images and skip decorative ones (
alt=""). - Forms: Tab through inputs. Does VoiceOver announce the label before each field? Are placeholders ignored?
- Buttons and links: Ensure they have accessible names (text
content or
aria-label). A button that only contains an icon must have anaria-label. - Dynamic content: If content updates (e.g., AJAX), you may need
to manage focus or use
aria-liveregions so VoiceOver announces changes.
✅ Example: Accessible button with icon
<button aria-label="Close">
<i class="bi bi-x"></i>
</button>
Without aria-label,
VoiceOver might read "button" with no context.
2.4 Common VoiceOver Issues and How to Fix Them
alt; for buttons, no text content or
aria-label.Fix: Add
alt to images, or
aria-label / aria-labelledby to interactive
elements.
<h2> followed by <h4>).Fix: Restructure headings so they don't skip levels. Use CSS to style them, not HTML level.
<input> not associated with a
<label>.Fix: Use
<label for="id"> matching
the input's id, or wrap the input inside the label.
3. Color & Contrast: Make Your Content Readable for Everyone
Good color contrast is essential for users with low vision, color blindness, or anyone reading in bright sunlight. WCAG defines specific contrast ratios that text and interactive elements must meet.
3.1 WCAG 2.2 Contrast Requirements
The Web Content Accessibility Guidelines (WCAG) specify minimum contrast ratios between text and its background:
| Text Type | Minimum Ratio (AA) | Enhanced Ratio (AAA) |
|---|---|---|
| Normal text (<18pt or <14pt bold) | 4.5:1 | 7:1 |
| Large text (≥18pt or ≥14pt bold) | 3:1 | 4.5:1 |
| User interface components (icons, focus indicators) | 3:1 | — |
3.2 How to Check Contrast
There are many tools to verify contrast ratios. Our own LynxA11y includes a dedicated Color Contrast tab that automatically lists all elements with insufficient contrast, along with the exact colors and ratio.
✅ Using LynxA11y Contrast Tab:
- Run an audit on any URL.
- Click the "Color Contrast" tab.
- See a list of all elements that fail contrast requirements.
- Each card shows the foreground/background colors and the measured ratio.
- Click "Suggest alternatives" to get color ideas that would pass.
Other excellent tools:
- WebAIM Contrast Checker
- Coolors Contrast Checker
- Browser DevTools (inspect element → color picker shows contrast ratio).
3.3 Building an Accessible Color Palette
When designing a new site, start with a palette that works for everyone. Here's a simple approach:
🎨 Good palette (passes AA):
Primary blue on white (#2563eb / #ffffff) → ratio 8.5:1 (pass AAA).
🚫 Problematic palette (fails):
Yellow (#fbbf24) on white → ratio 1.4:1 (fail). Unreadable.
Quick tip: Choose a primary color, then automatically generate accessible tints and shades using tools like Accessible Colors.
3.4 Common Contrast Issues & Fixes
Fix: Add a semi‑transparent overlay (e.g., a dark gradient) behind the text. Use
background-color with
opacity or a pseudo‑element.
Fix: Ensure
:focus styles have at least
3:1 contrast with the background. A thick, high‑contrast outline or ring
is best.
:focus-visible {
outline: 3px solid #2563eb;
outline-offset: 2px;
}
Fix: In addition to color, provide a non‑color cue like underlining, a bold weight, or an icon.
3.5 Designing for Color Blindness
About 1 in 12 men and 1 in 200 women have some form of color vision deficiency. Never rely on color alone to convey information.
✅ Good example (form validation):
✓ Green border + check icon – passes even if colors are indistinguishable.
❌ Bad example:
Valid – relies entirely on green colour.
Use tools like Toptal’s Color Filter to simulate how your site looks to people with different types of color blindness.
3.6 WCAG 2.2 Success Criteria Quick Reference
- 1.4.3 Contrast (Minimum) (Level AA): 4.5:1 for normal text, 3:1 for large text.
- 1.4.6 Contrast (Enhanced) (Level AAA): 7:1 for normal text, 4.5:1 for large text.
- 1.4.11 Non‑text Contrast (Level AA): UI components and focus indicators must have at least 3:1 contrast against adjacent colors.