Nearly half the websites we scanned had text without enough contrast to read comfortably. More than a third had at least one link that a screen reader announces as just "link", with nothing after it.
We pulled 1,025 websites that had been run through a free website accessibility checker between March and September 2026, and counted which problems showed up most often. Most of the list is small, repetitive, and fixable in a few lines of HTML or CSS. That's the good news. The bad news is that the same handful of mistakes keeps shipping to production.
Key takeaways
- Low color contrast was the most common issue, affecting 46.9% of sites.
- Three of the top ten are the same bug: a link, button or iframe with no name that assistive technology can announce.
- Most fixes take one attribute or one CSS rule, and they usually live in shared components, so one change fixes every page.
How we got the numbers
The method affects how you should read the results, so here it is up front:
- One result per site. Each website counts once, using its most recent completed scan, with
www.stripped soexample.comandwww.example.comcount as one site. Test domains were excluded. - More than the home page. About 40% of the scans crawled several pages of a site. The rest checked a single page, usually the home page. A site counts as having an issue if it showed up on any scanned page, so sites with more pages scanned had more chances to be flagged.
- Not a random sample. Just over half the sites were scanned as part of industry samples of business websites. The rest were submitted by people checking their own or their clients' sites, some of whom probably already suspected problems.
- Two rule sets. Most checks come from axe-core, the open-source engine built by Deque that also powers Lighthouse's accessibility audit. The rest are custom checks added on top, including link text quality and tap target size. Those are marked in the table.
- Merged image rules. axe reports missing alt text on
, SVGs, image inputs,andas separate rules. We merged them into one row because the fix and the user impact are the same. - Contrast is undercounted. A scanner can only measure contrast when it can read both colors, so text over images, gradients and video is left for manual review and isn't counted here.
- A snapshot in time. Each result reflects one scan between March and September 2026. Some sites may have fixed issues since, and others may have added new ones.
- Automated testing covers only part of WCAG. No scanner can tell you whether your alt text is accurate, whether focus order makes sense, or whether a custom dropdown works with a keyboard. Treat these numbers as a floor.
The top 10
| Rank | Issue | WCAG | Level | Sites affected |
|---|---|---|---|---|
| 1 | Low color contrast | 1.4.3 | AA | 46.9% (481) |
| 2 | Links with no accessible name | 2.4.4, 4.1.2 | A | 38.8% (398) |
| 3 | Touch targets under 44×44px* | 2.5.5 | AAA | 34.5% (354) |
| 4 | Images with no text alternative | 1.1.1 | A | 20.1% (206) |
| 5 | Skipped heading levels | Best practice | — | 14.0% (143) |
| 6 | Iframes with no title | 4.1.2 | A | 12.2% (125) |
| 7 | Buttons with no accessible name | 4.1.2 | A | 10.3% (106) |
| 8 | Generic link text ("click here")* | 2.4.4 | A | 9.9% (101) |
| 9 | ARIA attributes the element doesn't support | 4.1.2 | A | 9.5% (97) |
| 10 | Zoom disabled in the viewport meta tag | 1.4.4 | AA | 7.7% (79) |
- Custom check, not part of axe-core.

For comparison, the WebAIM Million 2026 found detectable WCAG failures on 95.9% of the top one million home pages, with an average of 56.1 errors per page. Its contrast failure rate (83.9%) is far higher than ours. Part of that gap comes from the different sample. The rest is down to how axe works: it only reports a contrast failure when it can measure both colors, so text over images and gradients is left for manual review and doesn't get counted.
1. Low color contrast (46.9%)
WCAG 1.4.3 requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (24px, or about 18.7px bold). The failures we see most are light grey body text, pale form labels, and white text on brand-colored buttons.
A typical example:
/* 4.13:1 — fails for normal-size text */
.alert {
background: #e53e3e;
color: #fff;
}
That red looks fine at a glance, but it falls just short. A slightly darker shade passes without changing the design much:
/* 5.47:1 — passes AA */
.alert {
background: #c53030;
color: #fff;
}
For AAA (7:1), #9b2335 gets you to 7.82:1. Don't trust your eyes on this one. Chrome DevTools' color picker shows the ratio live as you adjust the color.
2. Links with no accessible name (38.8%)
This is axe's link-name rule. It fires when a link has no text a screen reader can announce. The usual culprit is an icon link: social icons in the footer, a logo image with no alt text inside a link, a cart icon in the header.
<a href="https://github.com/acme">
<svg viewBox="0 0 24 24"><path d="..."/>svg>
a>
<a href="https://github.com/acme" aria-label="Acme on GitHub">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="..."/>svg>
a>
aria-label is fine here because the link has no visible text for it to conflict with. Hiding the SVG stops some screen readers from trying to read it as well.
These are easy to miss by eye, because the icon looks perfectly clear on screen. A browser-based checker finds them in seconds. axe DevTools, WAVE and this free accessibility checker Chrome extension all list every unnamed link on the page you have open.
3. Touch targets under 44×44px (34.5%)
This comes from a custom check, and it is stricter than WCAG's AA requirement. It uses the 44×44 CSS pixel size from WCAG 2.5.5, which is Level AAA. WCAG 2.2 added 2.5.8 at Level AA with a lower minimum of 24×24px, plus a spacing exception. So a flagged site won't necessarily fail AA. A 20px close button is still hard to hit for someone with a tremor, or for anyone holding a phone on a moving bus.
Inline links inside a paragraph are exempt from both WCAG criteria and from this check. The problems are usually standalone controls: icon buttons, carousel dots, pagination numbers and footer social icons.
.icon-button {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 44px;
min-height: 44px;
}
The icon itself can stay 20px. The extra space around it becomes tappable without changing how the button looks.
4. Images with no text alternative (20.1%)
Every meaningful image needs a text alternative (WCAG 1.1.1). Decorative images need an empty one so screen readers skip them.
<img src="q3-revenue.png" alt="Revenue grew 18% in Q3, from $2.1M to $2.5M">
<img src="divider-flourish.svg" alt="">
An empty alt="" works on its own, with no need for role="presentation" alongside it. The failure is leaving the attribute out entirely. Some screen readers then fall back to the file name, and "IMG underscore 4 0 3 2 dot jpeg" helps nobody.
For inline SVGs that carry meaning, add a role and a name:
<svg role="img" aria-label="4.8 out of 5 stars" viewBox="0 0 100 20">...svg>
Charts, logos and images inside links each need slightly different alt text. This WCAG 2.1 AA developer guide has code fixes for each case, plus forms and focus management.
5. Skipped heading levels (14.0%)
An followed directly by an isn't a WCAG failure by itself; axe treats heading order as a best practice. It still matters. Screen reader users often jump from heading to heading to get the shape of a page, and a skipped level suggests a section is missing.
The usual cause is picking a heading level for its default font size. Choose the level from the document structure, then style it with CSS:
<h2>Pricingh2>
<h3 class="text-small">Monthly plansh3>
6. Iframes with no title (12.2%)
Embedded maps, videos, booking widgets and chat tools often arrive as a pasted with no title. Screen readers then announce "frame" and give no hint of what's inside.
<iframe
src="https://www.google.com/maps/embed?pb=..."
title="Map showing our office at 120 Main Street"
loading="lazy">
iframe>
If a third-party script injects the iframe, look for a title option in the vendor's settings. If there isn't one, file an issue with them.
7. Buttons with no accessible name (10.3%)
This is the same problem as #2, applied to . Hamburger menus, close icons and play buttons are the usual offenders.
<button type="button" aria-label="Close dialog">
<svg aria-hidden="true" viewBox="0 0 24 24">...svg>
button>
If there's room for visible text, use it. A button that says "Close" works for everyone, including voice control users, who otherwise have to guess what to call an icon.
8. Generic link text (9.9%)
This custom check flags links that say "click here", "read more", "learn more" and similar. WCAG 2.4.4 (Level A) lets a link's purpose come from its context, such as the sentence or list item around it. A "Read more" under a blog card title isn't automatically a failure. Requiring the link text to make sense on its own is 2.4.9, which is AAA.
It's still worth fixing. Screen reader users often pull up a list of every link on the page, and ten "Read more" entries in a row tell them nothing.
The common quick fix is aria-label="Read more about our pricing update", and it creates a new problem. The accessible name no longer starts with the visible text, which fails WCAG 2.5.3 (Label in Name). A voice control user who says "click read more" may get no response. Keep the visible words at the start of the name and add the rest as visually hidden text:
<a href="/blog/pricing-update">
Read more<span class="visually-hidden"> about our pricing updatespan>
a>
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
9. ARIA attributes the element doesn't support (9.5%)
axe's aria-allowed-attr rule catches ARIA states used on roles that don't support them. A pattern we see often is a pricing toggle built from buttons:
<button type="button" aria-selected="true">Monthlybutton>
<button type="button" aria-selected="false">Yearlybutton>
aria-selected belongs to tabs, listbox options and grid cells. A toggle button uses aria-pressed:
<button type="button" aria-pressed="true">Monthlybutton>
<button type="button" aria-pressed="false">Yearlybutton>
Screen readers generally ignore unsupported attributes, so users never hear the state you meant to expose. That's a WCAG 4.1.2 failure. When you're unsure, the ARIA in HTML spec lists what each element accepts.
10. Zoom disabled in the viewport meta tag (7.7%)
This one usually comes from an old template or a copied snippet:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="viewport" content="width=device-width, initial-scale=1">
Blocking zoom fails WCAG 1.4.4 (Resize Text) and shuts out people with low vision. Safari on iOS has ignored user-scalable=no since iOS 10, but many Android browsers still respect it.
The tag is often added to stop iOS Safari zooming in when someone taps a form field. Safari only does that when the input's font size is below 16px, so fix that instead:
input, select, textarea {
font-size: 16px;
}
Once the restriction is gone, pinch-zoom your pages on a real phone. Fixed headers and full-screen overlays are the parts most likely to need a tweak.
Beyond the top 10
Just below the top ten:
- Missing
autocompleteon personal data fields (7.5%). WCAG 1.3.5 (AA) asks for it on fields like name, email and phone, and it saves everyone typing:. - Links in body text marked only by color (5.9%). Keep the underline.
- Interactive controls nested inside each other (5.7%), such as a button inside a link.
- **No
langattribute on **(4.2%). One attribute tells screen readers which language to speak. - Form inputs with no label (4.0%). Rarer than you might expect, but a form with this bug is often unusable with a screen reader.
Why this is worth an afternoon
People who use screen readers, keyboards, zoom or voice control hit these bugs every day, and many of them leave rather than fight the page.
In the US there's a legal angle too. Seyfarth Shaw's annual tracking shows federal website accessibility lawsuits rose 27% to 3,117 in 2025, and UsableNet counts more than 5,000 digital accessibility suits once state courts are included. The issues in this table are also the easiest to spot. Anyone with a free tool can find them in seconds, plaintiffs' firms included.
Accessibility overlays won't close the gap. A JavaScript widget can't reliably write accurate alt text or fix your heading structure. In 2025, the FTC ordered accessiBe to pay $1 million over claims that its tool could make any website compliant. EcomBack found that 22.6% of web accessibility lawsuits in the first half of 2025 targeted sites that already had an overlay installed.
Catch them before they ship
Everything in the top 10 shows up in your markup, so it can be tested automatically. If you already use Playwright, adding axe takes a few lines:
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test('home page has no detectable accessibility violations', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.analyze();
expect(results.violations).toEqual([]);
});
Filtering by WCAG tags leaves out axe's best-practice rules, including heading order. Add 'best-practice' to the list if you want those too, and add 'wcag22aa' for rules tagged to WCAG 2.2.
Start with one page per template (home, an article, a form, checkout) rather than every URL. Most of these bugs live in shared components, so fixing the header once fixes it everywhere.
Then do what no automated test can. Tab through your key flows with only a keyboard, and listen to them with a screen reader: VoiceOver on Mac, NVDA on Windows.
Fixing the ten issues above clears the problems scanners flag most often. Manual testing is how you find the rest.
This article is for informational purposes only and does not constitute legal advice.
