Six Failures Cause Most of the Web’s Accessibility Errors. Here Is Each Fix.

Close-up of colour swatches fanned out, showing tones of varying lightness side by side

Every year WebAIM scans the homepages of the top million websites and publishes what it finds. The 2026 edition reported that 95.9 percent still fail WCAG 2, with detected errors per page up roughly ten percent year over year, described as the first regression after several years of gradual improvement.

The number that gets quoted is the 95.9. The number that is actually useful is the concentration: the same small set of failure types has accounted for the overwhelming majority of detected errors, year after year, for as long as the study has run.

That concentration is the good news buried in a bad statistic. The web is not failing because accessibility is hard. It is failing on six things, all of which live in templates, and all of which a competent frontend developer can fix in a week.

1. Low contrast text

The most common failure by a wide margin. Body text at 4.5:1 against its background, large text and UI component boundaries at 3:1. That is the whole rule.

It fails because designers pick greys by feel on a colour accurate laptop in a well lit room, and because placeholder text, disabled states, and footer copy get chosen last and checked never.

The fix is not to check pages. It is to check tokens. Compute the ratios for every text colour in your palette against every surface it can land on, once, and correct the palette. If your muted grey is 3.7:1 you do not have a page problem, you have one variable that is wrong everywhere.

/* before: #6d6d76 on #0f0f0f = 3.74:1, fails AA for body text */
--color-text-muted: #6d6d76;

/* after: 4.70:1, passes */
--color-text-muted: #7d7d86;

One line, entire site. Watch specifically for text over images, gradients, and video, where the effective background changes per asset. Those need a scrim rather than a palette change.

2. Missing alternative text on images

Second most common, and the one most often fixed badly. An image with no alt attribute causes a screen reader to fall back to announcing the filename, which is how users end up hearing a string of hex characters.

The rule people miss: decorative images need an empty alt, not a missing one, and not a description.

<!-- decorative: correctly skipped -->
<img src="divider.svg" alt="">

<!-- informative: describes purpose, not appearance -->
<img src="chart.png" alt="Revenue grew from 1.2M to 3.4M between 2024 and 2026">

<!-- functional: describes the action, not the icon -->
<button><img src="trash.svg" alt="Delete item"></button>

Structurally, make alt a required prop on your image component. Not optional with a default of empty string, required, so that omitting it is a type error and the developer has to make a decision. Most alt text problems are not disagreements about wording, they are the absence of a moment where anyone was forced to think about it.

3. Empty links

A link containing only an icon, only an image without alt, or nothing at all. The screen reader announces link and then the URL, which is useless, and keyboard users tab onto something that gives no indication of where it goes.

Social icons in the footer are the classic offender. So are logo links, arrow buttons in carousels, and card wrappers where the whole card is an anchor with the text nested three levels down in a way that produces an empty accessible name.

<!-- broken -->
<a href="/x"><svg>...</svg></a>

<!-- fixed: visible text hidden from sight but present in the tree -->
<a href="/x">
  <svg aria-hidden="true" focusable="false">...</svg>
  <span class="visually-hidden">Follow us on X</span>
</a>

Use a clip based visually-hidden utility. Not display none, not visibility hidden, not zero width. Those remove the element from the accessibility tree and you are back where you started.

4. Missing form input labels

The failure with the highest real world cost, because forms are where transactions happen. An input with no programmatic label is an input a screen reader user cannot identify.

Placeholder text is not a label. It disappears on focus, it usually fails contrast, and assistive technology support for treating it as a name is inconsistent. Search fields and newsletter signups fail this constantly because the design called for a clean box with no visible label.

<!-- visible label, best option -->
<label for="email">Email address</label>
<input id="email" type="email" autocomplete="email">

<!-- design forbids a visible label -->
<label for="q" class="visually-hidden">Search products</label>
<input id="q" type="search" placeholder="Search">

While you are in there, add autocomplete tokens. They are a separate WCAG criterion and they measurably reduce errors for everyone.

5. Empty buttons

Same shape as empty links, different consequence. Icon only buttons with no accessible name: hamburger menus, close buttons on modals, quantity steppers, filter toggles.

<button aria-label="Close dialog">
  <svg aria-hidden="true" focusable="false">...</svg>
</button>

One caution on aria-label: it overrides any visible text inside the element. If a button reads Add to cart on screen and carries an aria-label of Add, a speech input user saying the visible words will not activate it. Only reach for aria-label when there is no visible text at all.

6. Missing document language

The cheapest fix in the entire list and it still appears on a large fraction of homepages.

<html lang="en">

Without it, a screen reader reads your content using whatever voice and pronunciation rules it defaults to. Spanish text read by an English synthesiser is not slightly awkward, it is often incomprehensible.

If you run multiple locales, verify that the attribute actually changes per locale rather than being hardcoded in a shared shell. And mark inline language changes where a section genuinely switches language, using lang on the containing element.

Doing all six in one pass

These are template concerns, not content concerns, which is what makes them tractable. A realistic sequence:

  • Run axe-core across your main templates and export the violation list. An afternoon.
  • Fix the colour palette at the token level. Half a day, mostly spent arguing about grey.
  • Make alt required on the image component and work through the compile errors. One to two days depending on how much you shipped before anyone asked.
  • Sweep icon only links and buttons for accessible names. Half a day.
  • Label every input and add autocomplete tokens. Half a day.
  • Set lang correctly per locale. Ten minutes.
  • Add axe-core to CI so none of it comes back.

That will not make a site conformant. Automated tooling detects only a fraction of WCAG criteria, and the barriers that actually stop people, broken focus order, keyboard traps, unannounced state changes, need manual testing with real assistive technology.

But it removes the majority of your detected errors, it is genuinely a week of work, and it is the difference between a site that is hostile by neglect and one that has a real remediation baseline to build on.


I audit and remediate frontends against WCAG 2.1 and 2.2 AA, with a focus on ecommerce. Write to me at serbeldiaz@gmail.com.

CATEGORIES:

Compliance-Frontend

No responses yet

Leave a Reply

Your email address will not be published. Required fields are marked *

Latest Comments

No comments to show.