🦊 Web Accessibility Best Practices

Practical tips to make your site inclusive for everyone.

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>
Pro tip: Test your page with a screen reader (like VoiceOver on macOS) to experience how your HTML structure is announced. You'll quickly spot missing labels or confusing hierarchies.

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.
Tip: When VoiceOver is active, the keyboard and trackpad gestures change. Use Ctrl + Option + →/← to navigate by items on macOS. On iOS, explore with one finger and double-tap to activate.
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 an aria-label.
  • Dynamic content: If content updates (e.g., AJAX), you may need to manage focus or use aria-live regions 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
Cause: The element has no accessible name. For images, missing alt; for buttons, no text content or aria-label.
Fix: Add alt to images, or aria-label / aria-labelledby to interactive elements.
Cause: Heading levels are not hierarchical (e.g., <h2> followed by <h4>).
Fix: Restructure headings so they don't skip levels. Use CSS to style them, not HTML level.
Cause: <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
Important: These ratios apply to text and images of text. Decorative elements (like a background gradient) are exempt, but any text within them must still pass.
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:

  1. Run an audit on any URL.
  2. Click the "Color Contrast" tab.
  3. See a list of all elements that fail contrast requirements.
  4. Each card shows the foreground/background colors and the measured ratio.
  5. Click "Suggest alternatives" to get color ideas that would pass.

Other excellent tools:

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):

#2563eb #111827 #f3f4f6

Primary blue on white (#2563eb / #ffffff) → ratio 8.5:1 (pass AAA).

🚫 Problematic palette (fails):

#fbbf24 #ffffff

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
Problem: Text overlaid on photos often becomes unreadable.
Fix: Add a semi‑transparent overlay (e.g., a dark gradient) behind the text. Use background-color with opacity or a pseudo‑element.
Problem: The default browser focus outline is sometimes overridden or too subtle.
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;
}
Problem: Users with color blindness may not distinguish a colored link from normal text.
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.
Ready to check your site? Use LynxA11y’s Color Contrast tab to instantly see which elements need attention. Every violation includes a direct link to the WCAG guide and alternative color suggestions.