Why These Failures Keep Appearing
After scanning thousands of websites for WCAG compliance, we've identified the same issues appearing on the vast majority of sites. The WebAIM Million study confirms it: 96.3% of home pages have detectable WCAG 2 failures—and most of those failures come from a short list of common mistakes.
The good news? These failures are fixable. In most cases, you can resolve them in minutes with the right knowledge. This guide covers the ten most common WCAG failures, explains why they matter, and provides practical code examples for fixing each one.
Before diving in, consider running a free accessibility scan on your site to see which of these issues affect you. Then use this guide as your remediation playbook.
Missing Alternative Text for Images
WCAG Criterion: 1.1.1 Non-text Content (Level A)
Missing alt text is the single most common accessibility failure, appearing on over 55% of all websites. When images lack text alternatives, screen reader users encounter "image" or "graphic" with no context about what they're looking at.
Why It Matters
Images often convey critical information—product photos, instructional diagrams, team headshots, infographics. Without alt text, blind and low-vision users miss this content entirely. Search engines also rely on alt text to understand images, so fixing this improves SEO as well.
❌ Common Mistakes
<!-- Missing alt entirely --> <img src="product.jpg"> <!-- Placeholder alt --> <img src="chart.png" alt="image"> <!-- Filename as alt --> <img src="hero.jpg" alt="IMG_4521.jpg"> <!-- Keyword stuffing --> <img src="shoes.jpg" alt="shoes sneakers running shoes athletic shoes buy shoes">
✓ Proper Implementation
<!-- Descriptive alt text -->
<img src="product.jpg"
alt="Red Nike Air Max sneakers, side view">
<!-- Decorative image (empty alt) -->
<img src="decorative-line.svg" alt="">
<!-- Complex image with longer description -->
<img src="chart.png"
alt="Bar chart showing 40% increase in sales from Q1 to Q4 2025">💡 Quick Tips
- • Be concise: Aim for under 125 characters when possible
- • Don't start with "Image of" or "Picture of"—screen readers announce it's an image
- • Empty alt for decorative images: Use
alt=""(not omitting the attribute) - • Describe function, not appearance: For a search icon button, use "Search" not "magnifying glass"
Insufficient Color Contrast
WCAG Criterion: 1.4.3 Contrast (Minimum) (Level AA)
Low contrast text appears on over 80% of websites, making it the most widespread accessibility issue. Light gray text on white backgrounds is the classic offender—trendy in design mockups but unreadable for many users.
Required Contrast Ratios
Normal Text (<24px)
4.5:1
Minimum contrast ratio required
Large Text (≥24px or 18.5px bold)
3:1
Minimum contrast ratio required
Common Low-Contrast Offenders:
💡 How to Fix
- Use a contrast checker tool (WebAIM Contrast Checker, Stark, or browser DevTools)
- Audit placeholder text—it often fails contrast requirements
- Check text over images—add overlays or text shadows if needed
- Don't rely on hover states for critical information
Missing or Improper Form Labels
WCAG Criterion: 3.3.2 Labels or Instructions (Level A)
Form inputs without proper labels leave screen reader users guessing about what information to enter. Placeholder text alone doesn't count—it disappears when users start typing and isn't announced consistently by assistive technology.
❌ Common Mistakes
<!-- Placeholder instead of label --> <input type="email" placeholder="Email"> <!-- Label not associated --> <label>Email</label> <input type="email" id="email"> <!-- Hidden label (sometimes okay) --> <label class="sr-only">Email</label> <input type="email">
✓ Proper Implementation
<!-- Explicit label association -->
<label for="email">Email address</label>
<input type="email" id="email">
<!-- Implicit label (wrapping) -->
<label>
Email address
<input type="email">
</label>
<!-- With aria-labelledby -->
<span id="email-label">Email</span>
<input type="email"
aria-labelledby="email-label">What About Visually Hidden Labels?
Sometimes designers want a cleaner look without visible labels. You can visually hide labels while keeping them accessible, but this should be used sparingly and only when the input's purpose is obvious from context (like a search box with a magnifying glass icon).
.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;
}Empty Links and Buttons
WCAG Criterion: 2.4.4 Link Purpose (Level A) and 4.1.2 Name, Role, Value (Level A)
Icon-only buttons and links are everywhere—social media icons, hamburger menus, close buttons, arrow navigation. Without accessible names, screen readers announce them as "button" or "link" with no indication of what they do.
❌ Common Mistakes
<!-- Icon button without label --> <button> <svg><!-- hamburger icon --></svg> </button> <!-- Empty link --> <a href="/twitter"> <i class="fa-twitter"></i> </a> <!-- Image link without alt --> <a href="/"> <img src="logo.svg"> </a>
✓ Proper Implementation
<!-- aria-label for icon buttons --> <button aria-label="Open menu"> <svg aria-hidden="true">...</svg> </button> <!-- Visually hidden text --> <a href="/twitter"> <i class="fa-twitter" aria-hidden="true"></i> <span class="sr-only">Follow us on Twitter</span> </a> <!-- Alt text for image links --> <a href="/"> <img src="logo.svg" alt="RatedWithAI home"> </a>
💡 Pro Tip: Hide Decorative Icons
When you add an accessible name to a button, hide the icon from assistive technology using aria-hidden="true". This prevents screen readers from announcing both the icon and the label (e.g., "hamburger, open menu").
Missing Document Language
WCAG Criterion: 3.1.1 Language of Page (Level A)
This is the easiest fix on the list but often overlooked. Without a language declaration, screen readers may use the wrong pronunciation rules, making content incomprehensible. French words read with English pronunciation? Not a great experience.
❌ Missing Language
<!DOCTYPE html> <html> <head>...</head> <body>...</body> </html>
✓ With Language Declared
<!DOCTYPE html> <html lang="en"> <head>...</head> <body>...</body> </html> <!-- For other languages --> <html lang="es"> <!-- Spanish --> <html lang="fr"> <!-- French --> <html lang="de"> <!-- German -->
For pages with mixed languages, use the lang attribute on specific elements. See 3.1.2 Language of Parts for details.
Missing or Low-Contrast Focus Indicators
WCAG Criterion: 2.4.7 Focus Visible (Level AA)
Removing the default focus outline is one of the most common (and harmful) CSS practices. Without visible focus indicators, keyboard users can't tell which element they're interacting with. It's like hiding the mouse cursor.
❌ Never Do This
/* This breaks keyboard navigation */
*:focus {
outline: none;
}
button:focus,
a:focus {
outline: 0;
}✓ Better Approaches
/* Use :focus-visible for keyboard-only focus */
button:focus-visible,
a:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* Custom focus styles that match your design */
.btn:focus-visible {
outline: none;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5);
}
/* High contrast focus for dark backgrounds */
a:focus-visible {
outline: 2px solid #fff;
outline-offset: 2px;
border-radius: 2px;
}💡 Why :focus-visible?
The :focus-visible selector only shows focus indicators when keyboard navigation is detected, not on mouse clicks. This gives you clean visuals for mouse users while maintaining accessibility for keyboard users. It's supported in all modern browsers.
Broken Heading Hierarchy
WCAG Criterion: 1.3.1 Info and Relationships (Level A) and 2.4.6 Headings and Labels (Level AA)
Headings aren't just for styling—they create a navigable document outline. Screen reader users jump between headings to scan content. Skipping levels or using headings inconsistently breaks this navigation pattern.
❌ Common Mistakes
<!-- Skipping heading levels --> <h1>Page Title</h1> <h4>Section Title</h4> <!-- Skipped h2, h3 --> <!-- Multiple h1s --> <h1>Logo</h1> <h1>Page Title</h1> <h1>Section</h1> <!-- Using headings for styling --> <h3>This small text looks nice</h3>
✓ Proper Hierarchy
<h1>Page Title</h1>
<h2>Section 1</h2>
<h3>Subsection 1.1</h3>
<h3>Subsection 1.2</h3>
<h2>Section 2</h2>
<h3>Subsection 2.1</h3>
<h4>Detail 2.1.1</h4>
<!-- Style with classes, not heading level -->
<p class="text-sm font-semibold">
This small text looks nice
</p>Quick Test
Install the WAVE browser extension and look at the Structure tab. You'll see your heading outline instantly. If it doesn't read like a table of contents, fix it.
Links Not Distinguishable from Text
WCAG Criterion: 1.4.1 Use of Color (Level A)
If links are only distinguished by color (no underline or other visual cue), color-blind users may not recognize them as clickable. This is especially problematic when links are embedded in paragraphs of text.
❌ Color-Only Links
/* Only difference is color */
a {
color: #3b82f6;
text-decoration: none;
}✓ Multiple Visual Cues
/* Underline + color */
a {
color: #3b82f6;
text-decoration: underline;
}
/* Or underline on hover with high contrast */
a {
color: #3b82f6;
text-decoration: none;
font-weight: 600;
}
a:hover, a:focus {
text-decoration: underline;
}Low Non-Text Contrast
WCAG Criterion: 1.4.11 Non-text Contrast (Level AA)
UI components like form field borders, icons, and focus indicators also need sufficient contrast. A light gray input border on a white background may be too subtle for users with low vision to see.
Minimum: 3:1 Contrast Ratio
Unlike text (4.5:1), UI components only need 3:1 contrast. But this still catches many common designs.
❌ Light borders
#E5E7EB border (1.3:1 on white)
✓ Visible borders
#6B7280 border (4.6:1 on white)
Keyboard Traps
WCAG Criterion: 2.1.2 No Keyboard Trap (Level A)
Keyboard traps occur when users can Tab into a component but can't Tab out. This is common with modals, embedded media players, and custom widgets that capture keyboard events. Users get stuck and have to refresh the page.
Common Keyboard Trap Sources
- •Modal dialogs that don't trap focus properly (or trap it too aggressively)
- •Embedded content (iframes, video players) that capture all keyboard input
- •Custom widgets that use
event.preventDefault()on keydown events - •Date pickers and autocomplete dropdowns that don't close with Escape
✓ Modal Best Practices
// 1. Trap focus inside the modal
// 2. Allow Escape to close
// 3. Return focus to trigger element on close
dialog.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeModal();
triggerButton.focus(); // Return focus
}
});
// Use the native <dialog> element when possible
<dialog>
<button onclick="this.closest('dialog').close()">
Close
</button>
</dialog>Your Remediation Checklist
Here's a prioritized action plan for fixing these issues:
- 1Run an automated scan — Use RatedWithAI to identify issues on your site
- 2Add document language — One line fix:
<html lang="en"> - 3Fix alt text globally — Audit all images, add meaningful descriptions
- 4Restore focus indicators — Remove any
outline: nonewithout replacements - 5Label all form fields — Associate labels with inputs using
forattribute - 6Fix contrast issues — Use a contrast checker, aim for 4.5:1 minimum
- 7Do keyboard testing — Tab through your site, escape from all modals
For more detailed guidance, see our ADA Compliance Checklist and Website Accessibility Testing Guide.
Find Your Issues
Scan Your Site for WCAG Failures
Get a detailed report showing exactly which of these issues affect your site—with prioritized fixes.