Why Accessibility Matters
Accessible websites reach more users and rank better in search engines. Many accessibility best practices overlap with SEO best practices: semantic HTML, alt text, keyboard navigation, and clear content structure all help both users and search engines.
The 16 Checks
Every check ranked by impact. Start at the top and work down.
| # | Check | Category | Impact | Difficulty |
|---|---|---|---|---|
| 1 | Use semantic HTML elements | HTML | Critical | Easy |
| 2 | Add alt text to all images | Images | Critical | Easy |
| 3 | Ensure keyboard navigation works | Navigation | Critical | Medium |
| 4 | Maintain color contrast ratio 4.5:1 | Design | Critical | Easy |
| 5 | Add ARIA labels to interactive elements | ARIA | High | Easy |
| 6 | Use proper heading hierarchy | Structure | High | Easy |
| 7 | Add skip navigation link | Navigation | High | Easy |
| 8 | Label all form inputs | Forms | High | Easy |
| 9 | Provide video captions | Media | High | Medium |
| 10 | Use descriptive link text | Links | Medium | Easy |
| 11 | Avoid auto-playing media | UX | Medium | Easy |
| 12 | Add focus indicators | Design | Medium | Easy |
| 13 | Use lang attribute on html | HTML | Medium | Easy |
| 14 | Provide text alternatives for icons | Design | Low | Easy |
| 15 | Test with screen reader | Testing | Low | Medium |
| 16 | Run Lighthouse accessibility audit | Testing | Low | Easy |
Deep Dive: Every Check Explained
Detailed implementation guides with code examples for all 16 checks.
1 Use Semantic HTML Elements
Semantic elements like <nav>, <main>, <article>, <aside>, <header>, and <footer> convey meaning to assistive technologies. Screen readers use these landmarks to let users jump between page sections. Search engines also use them to understand content hierarchy.
# Bad: div soup with no meaning <div class="header">...</div> <div class="nav">...</div> <div class="main"> <div class="article">...</div> </div> # Good: semantic landmarks <header>...</header> <nav aria-label="Main">...</nav> <main> <article>...</article> </main> # WCAG criteria: 1.3.1 Info and Relationships (A), 2.4.1 Bypass Blocks (A)
2 Add Alt Text to All Images
Alt text serves two purposes: it describes the image for screen reader users and provides text context for search engines when images fail to load. Every <img> must have an alt attribute. Decorative images should use alt="" (empty alt) so screen readers skip them.
# Informative image: describe the content
<img src="team-meeting.jpg"
alt="Marketing team reviewing Q3 campaign results on a whiteboard">
# Functional image (link/button): describe the action
<a href="/">
<img src="logo.svg" alt="Clienvora homepage">
</a>
# Decorative image: empty alt
<img src="decorative-swirl.svg" alt="">
# Complex image: use long description
<img src="org-chart.png" alt="Company org chart"
aria-describedby="chart-desc">
<div id="chart-desc">CEO reports to board of directors. Three VPs report to CEO...</div>
# Bad alt text examples:
alt="image" # too vague
alt="photo.jpg" # filename is not a description
alt="click here" # describes action, not image
# WCAG criteria: 1.1.1 Non-text Content (A) 3 Ensure Keyboard Navigation Works
Every interactive element must be reachable and operable via keyboard alone. Users who cannot use a mouse rely on Tab, Shift+Tab, Enter, Space, and arrow keys. Test by unplugging your mouse and tabbing through every page.
# Tab order: elements receive focus in logical reading order
# Focus indicator: must be visible (never outline: none without replacement)
# Custom focus styles:
:focus-visible {
outline: 3px solid #C9A227;
outline-offset: 2px;
}
# Make custom elements focusable:
<div role="button" tabindex="0"
onkeydown="if(event.key==='Enter'||event.key===' ')doAction()">
Click me
</div>
# Avoid positive tabindex values (breaks natural order):
tabindex="0" # follows DOM order (correct)
tabindex="-1" # programmatically focusable only
tabindex="1" # NEVER use positive values
# Common keyboard traps to avoid:
- Modal dialogs that don't return focus on close
- Dropdown menus that trap Tab key
- Embedded iframes without keyboard access
# WCAG criteria: 2.1.1 Keyboard (A), 2.4.7 Focus Visible (AA) 4 Maintain Color Contrast Ratio 4.5:1
Text must have sufficient contrast against its background. WCAG AA requires 4.5:1 for normal text and 3:1 for large text (18pt+ or 14pt+ bold). Non-text elements like icons, borders, and focus indicators also need 3:1 contrast.
# Minimum contrast ratios (WCAG 2.1 AA): Normal text (<18pt): 4.5:1 Large text (≥18pt): 3:1 Large bold text (≥14pt): 3:1 UI components/borders: 3:1 # How to check contrast: 1. Chrome DevTools: inspect element → color picker shows ratio 2. WebAIM Contrast Checker: webaim.org/resources/contrastchecker 3. axe DevTools: highlights contrast failures automatically # Common failures: - Light gray text on white (#999 on #FFF = 2.85:1 FAIL) - Placeholder text in form fields - Text over images without overlay - Link text indistinguishable from body text # WCAG criteria: 1.4.3 Contrast Minimum (AA), 1.4.6 Contrast Enhanced (AAA), 1.4.11 Non-text Contrast (AA)
5 Add ARIA Labels to Interactive Elements
ARIA attributes provide accessible names and descriptions when HTML alone cannot. The first rule of ARIA: do not use ARIA if a native HTML element already provides the semantics. Always prefer <button> over <div role="button">.
# aria-label: provides accessible name when no visible text <button aria-label="Close dialog"> <svg>...X icon...</svg> </button> # aria-labelledby: references visible text elsewhere on page <h2 id="checkout-title">Shipping Address</h2> <form aria-labelledby="checkout-title">...</form> # aria-describedby: adds supplementary description <input type="password" aria-describedby="pw-hint"> <span id="pw-hint">Must be 8+ characters with one number</span> # aria-expanded: indicates collapsible state <button aria-expanded="false" aria-controls="menu1"> Menu </button> <ul id="menu1" hidden>...</ul> # aria-hidden: removes element from accessibility tree <span aria-hidden="true">★</span> <!-- decorative star --> # aria-live: announces dynamic content changes <div aria-live="polite">3 items in cart</div> # WCAG criteria: 4.1.2 Name, Role, Value (A), 1.3.1 Info and Relationships (A)
6 Use Proper Heading Hierarchy
Headings create an outline that screen readers use for navigation. Never skip heading levels (e.g., h2 to h4). Every page should have exactly one <h1>. Use headings for structure, not for styling.
# Correct heading hierarchy:
<h1>Page Title</h1>
<h2>Section One</h2>
<h3>Subsection</h3>
<h3>Subsection</h3>
<h2>Section Two</h2>
<h3>Subsection</h3>
# Bad: skipping levels for visual styling
<h1>Title</h1>
<h4>Looks smaller</h4> <!-- WRONG: skipped h2 and h3 -->
# WCAG criteria: 1.3.1 Info and Relationships (A), 2.4.6 Headings and Labels (AA) 7 Add Skip Navigation Link
A skip link lets keyboard users bypass repetitive navigation and jump directly to the main content. It should be the first focusable element on the page and become visible on focus.
# HTML: <a href="#main-content" class="skip-link">Skip to main content</a> <nav>...</nav> <main id="main-content">...</main> # CSS: .skip-link { position: absolute; top: -40px; left: 0; background: #C9A227; color: #0F172A; padding: 8px 16px; z-index: 100; font-weight: 600; transition: top 0.2s; } .skip-link:focus { top: 0; } # WCAG criteria: 2.4.1 Bypass Blocks (A)
8 Label All Form Inputs
Every form input needs a visible label associated with it using the for attribute or by wrapping the input in a <label> element. Placeholder text is not a substitute for labels it disappears when users type.
# Correct: explicit label with for/id
<label for="email">Email address</label>
<input type="email" id="email" name="email">
# Correct: implicit label (wrapping)
<label>
Email address
<input type="email" name="email">
</label>
# Error messages: link to input with aria-describedby
<label for="phone">Phone number</label>
<input type="tel" id="phone" aria-describedby="phone-error"
aria-invalid="true">
<span id="phone-error" role="alert">
Please enter a valid phone number
</span>
# Grouped inputs: use fieldset and legend
<fieldset>
<legend>Shipping method</legend>
<label><input type="radio" name="ship" value="std"> Standard</label>
<label><input type="radio" name="ship" value="exp"> Express</label>
</fieldset>
# WCAG criteria: 1.3.1 Info and Relationships (A), 3.3.2 Labels or Instructions (A), 3.3.1 Error Identification (A) 9 Provide Video Captions
All video content with audio must have synchronized captions. Captions benefit deaf and hard-of-hearing users, non-native speakers, and users in sound-off environments. Use WebVTT format for HTML5 video.
10 Use Descriptive Link Text
Link text must make sense out of context. Screen readers often list all links on a page, so "click here" or "read more" are meaningless. Instead, describe the destination.
# Bad: <a href="/pricing">Click here</a> <a href="/blog/post">Read more</a> # Good: <a href="/pricing">View our pricing plans</a> <a href="/blog/post">Read the full accessibility guide</a> # WCAG criteria: 2.4.4 Link Purpose in Context (A)
11 Avoid Auto-Playing Media
Auto-playing audio or video can disorient screen reader users and make it difficult to navigate. If media must auto-play, provide a mechanism to pause or stop it within the first 3 seconds.
12 Add Focus Indicators
Focus indicators show keyboard users which element is currently active. Never remove them with outline: none without providing an alternative. Custom focus styles should be at least as visible as browser defaults.
# Never do this: *:focus { outline: none; } <!-- removes all focus indicators --> # Custom focus style: :focus-visible { outline: 3px solid #C9A227; outline-offset: 2px; border-radius: 4px; } # WCAG criteria: 2.4.7 Focus Visible (AA)
13 Use lang Attribute on HTML
The lang attribute tells screen readers which language to use for pronunciation. It also helps search engines determine the language of your content.
# Primary language: <html lang="en"> # Mixed language content: <p>The French word <span lang="fr">bonjour</span> means hello.</p> # WCAG criteria: 3.1.1 Language of Page (A), 3.1.2 Language of Parts (AA)
14 Provide Text Alternatives for Icons
Icon-only buttons and links must have accessible text. Use aria-label on the element or visually hidden text inside it.
# aria-label approach: <button aria-label="Search"> <svg>...magnifying glass...</svg> </button> # Visually hidden text: <button> <svg aria-hidden="true">...icon...</svg> <span class="sr-only">Search</span> </button> # CSS for sr-only: .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
15 Test with Screen Readers
Automated tools catch only 30-40% of accessibility issues. Manual screen reader testing is essential. Test with at least two screen readers across different platforms.
# Recommended screen readers: NVDA (Windows, free) - Download: nvaccess.org - Works with Firefox and Chrome - Toggle: NVDA + Space to enter focus mode JAWS (Windows, paid — 40-min demo mode) - Industry standard for enterprise - Best IE/Edge support - Virtual cursor: arrow keys to read VoiceOver (Mac/iOS, built-in) - Cmd + F5 to toggle on Mac - Navigate: VO + arrow keys (VO = Ctrl + Option) - Rotor: VO + U for page landmarks TalkBack (Android, built-in) - Settings → Accessibility → TalkBack - Swipe right/left to navigate - Double-tap to activate # What to test: - Can you reach every interactive element with Tab? - Do images have meaningful alt text? - Are form labels announced correctly? - Do error messages get announced? - Can you navigate by headings (NVDA: H key)? - Does the page make sense when read linearly?
16 Run Lighthouse Accessibility Audit
Lighthouse provides an automated accessibility score and identifies common issues. It is a starting point, not a complete audit. Pair it with axe DevTools for deeper analysis and manual testing.
WCAG 2.1 Success Criteria Mapping
How each check maps to official WCAG 2.1 success criteria.
Check → WCAG Criteria
Accessibility Testing Tools
Free and built-in tools to audit and validate your accessibility implementation.
WAVE
Browser extension that overlays accessibility errors and warnings directly on your pages. Shows contrast issues, missing alt text, ARIA errors, and structural problems visually.
Freeaxe DevTools
Browser extension by Deque Systems. Identifies WCAG violations with clear remediation guidance. Integrates into Chrome DevTools. The most accurate automated testing engine available.
FreeLighthouse
Built into Chrome DevTools (Audits tab). Runs an automated accessibility audit and provides a score from 0-100. Good starting point but catches only ~30% of issues.
FreeContrast Checker by WebAIM
Enter foreground and background colors to check WCAG AA and AAA contrast ratios. Also includes a color blindness simulator and link contrast analyzer.
FreeNVDA Screen Reader
Free, open-source screen reader for Windows. The most widely used screen reader for testing. Download from nvaccess.org. Works with Firefox and Chrome.
FreeVoiceOver
Built-in screen reader on macOS, iOS, and iPadOS. No installation needed. Toggle with Cmd+F5 on Mac. Test on iPhone with Settings → Accessibility → VoiceOver.
Built-in on MacRelated Checklists
Keep exploring the on-page SEO series. Every checklist follows the same structure.
Image SEO Optimization
Alt text, image formats, lazy loading, and image schema markup.
Headings & Structure
Heading hierarchy, content outlines, and semantic structure for SEO.
User Experience
Core Web Vitals, mobile UX, and usability best practices.
Structured Data & Schema.org
JSON-LD implementation, schema types, and rich results.
HTML Document Structure
Proper HTML semantics, document outline, and structural elements.
Technical SEO: Accessibility
Technical accessibility audit from an SEO perspective.
Frequently Asked Questions
Common questions about web accessibility and SEO.
Yes. Semantic HTML, alt text, proper heading hierarchy, and clear content structure are both accessibility requirements and SEO best practices. Google uses the same signals to understand page structure that screen readers use to navigate content. Sites with strong accessibility tend to have lower bounce rates, longer session durations, and better crawl efficiency — all of which correlate with higher rankings.
Web Content Accessibility Guidelines (WCAG) are international standards published by the W3C. WCAG 2.1 Level AA is the most commonly referenced standard for legal compliance under the ADA (US), EAA (EU), and AODA (Canada). WCAG is organized around four principles: Perceivable, Operable, Understandable, and Robust (POUR). Each principle contains success criteria at three conformance levels: A (minimum), AA (standard), and AAA (enhanced).
Use a combination of automated and manual testing. Run Lighthouse accessibility audit and axe DevTools for automated checks. Use WAVE to visualize issues on-page. Test keyboard navigation by tabbing through every interactive element. Test with screen readers: NVDA (free, Windows), JAWS (paid, Windows), and VoiceOver (built-in on Mac/iOS). Use WebAIM Contrast Checker for color contrast validation. Automated tools catch roughly 30-40% of accessibility issues — manual testing catches the rest.
In many countries, yes. In the US, the ADA has been interpreted by courts to apply to websites. The European Accessibility Act (EAA) requires digital products and services to be accessible by June 2025. Canada's AODA and the UK Equality Act have similar requirements. Non-compliance can result in lawsuits, fines, and reputational damage. In 2023 alone, over 4,600 accessibility lawsuits were filed in the US.
ARIA (Accessible Rich Internet Applications) attributes supplement HTML semantics when native elements cannot convey the role, state, or properties of a component. Use ARIA when there is no native HTML element that provides the needed semantics. The first rule of ARIA is: do not use ARIA if a native HTML element or attribute already exists. For example, use a <button> element instead of adding role="button" to a div.
WCAG 2.1 Level AA requires a contrast ratio of at least 4.5:1 for normal text (under 18pt or 14pt bold) and 3:1 for large text (18pt or 14pt bold and above). Non-text elements like icons, borders, and form fields also require a 3:1 contrast ratio against adjacent colors. Use the WebAIM Contrast Checker or Chrome DevTools to verify contrast ratios.