1.4.9 Images of Text (No Exception)

WCAG 2.2 · 1.4.9 AAA Perceivable

What it requires

Text must be presented as real, machine-readable text rather than as a picture of text. Under this Level AAA criterion, images of text may only be used where a particular presentation of text is essential (for example, a logotype, or a sample of a specific typeface where the exact rendering is the point) or where the image is purely decorative. Unlike its Level AA counterpart (1.4.5), there is no exception for images that are merely customizable or where the styling cannot easily be reproduced — if the content is text, it must be real text.

  • Low-vision users who enlarge text: images of text blur and pixelate when scaled, while real text stays crisp.
  • Users with custom styles who change font, spacing, or colours to read comfortably — an image ignores those overrides.
  • Screen-reader and braille users, when the image lacks an equivalent alt value or the text is part of a longer passage.
  • Anyone translating or selecting text, which is impossible inside an image.

How to detect it

Ways to find images of text
Check What to look for
Manual / visual Headings, banners, buttons, or quotes that look like styled text but are <img>, SVG <image>, or CSS background images.
Select & zoom Try to select the text with the cursor; zoom to 400%. Selectable, sharp text passes; un-selectable, blurry text is an image of text.
Screen reader Confirm the words are announced as text, not skipped or read only via alt.
Automated tools Tools like axe cannot reliably tell whether an image contains text, so this criterion needs human review.

How to fix it

  1. Replace the image with real text and reproduce its look using CSS (web fonts, colour, gradients, shadows).
  2. Reserve images of text for essential cases (logotypes, typeface specimens) or decorative use only.
  3. Where an image is unavoidable, provide an accurate text alternative.
<!-- Real text styled with CSS, not a picture -->
<h2 class="hero-title">Summer Sale — 40% off</h2>

Copy-paste tests

Automated coverage

There is no fully automated axe-core rule that proves text is real text and not a picture of text, so 1.4.9 needs manual review. Use the console check and steps below to surface candidates.

Run this in the browser console

find-images-of-text.js
// Surface images that may be images of text (read-only)
const suspects = [...document.querySelectorAll('img, svg image, [role="img"]')]
  .filter(el => {
    const alt = (el.getAttribute('alt') || el.getAttribute('aria-label') || '').trim();
    return alt.length > 12 || /\b(sale|off|title|heading|logo)\b/i.test(alt);
  });
suspects.forEach(el => { el.style.outline = '3px solid magenta'; });
console.table(suspects.map(el => ({
  tag: el.tagName, src: el.currentSrc || el.getAttribute('src') || '', alt: el.alt || el.getAttribute('aria-label') || ''
})));
console.log('Image-of-text candidates:', suspects.length);

What to check manually: open each highlighted image and confirm the words are not part of the picture — could they be reproduced as live text styled with CSS? Logotypes and brand wordmarks are exempt; everything else at 1.4.9 must be real text.