auditmysitev2.0.2

Content clipped when text spacing is increased

text-spacing/clipped

WCAG success criterion
1.4.12 (level AA)
Outcome class
Hint only. An automated check that by design reports review hints only: its findings are marked for manual review, never as confirmed violations.
Area
Accessibility, Visual Presentation
Default severity
medium
axe-core rule
text-spacing

Why we flag this

Users who increase line/letter/word spacing for readability lose content.

Fixed height/width with overflow:hidden on text containers; measured before and after overriding the text spacing, only newly clipped text counts.

What the rule checks

Scope. Rendered elements with text in the top document and its open shadow roots; only those with overflow: hidden can clip.

Expectation. Review (not a violation) when applying the 1.4.12 minimums (line height 1.5, paragraph spacing 2em, letter spacing 0.12em, word spacing 0.16em) makes a container clip text it did not clip before (Rendering::text_spacing_clip, a before/after pair measured by accessibility::probes): a fixed-height badge (20px at line-height 1.2) or a fixed-width, nowrap label. Content clipped already before the change (teasers cut by design, the 1x1 visually-hidden pattern) is not caused by spacing and not reported. A container exactly as tall as one line at 1.5 (24px) still fits; one that grows (min-height) or whose fixed height a script removes after load passes. Every newly clipped element is reported. The override is a constructed stylesheet adopted through the CSSOM, so a CSP style-src does not block it (visual_text_spacing_csp). Where the override does not reach the element (the page wins with a stronger !important), nothing was measured: the rule is recorded as not run (CapabilityMissing), never as a pass (visual_text_spacing_override_defeated).

Source. WCAG 2.2 SC 1.4.12 Text Spacing; W3C text spacing bookmarklet technique

Detection: shared; needs dom, computed_style, geometry.

Failing example

The check flags this for review. Corpus case visual_text_spacing_letter, element span#chip. The page may contain further findings for other rules.

visual_text_spacing_letter.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Button label clipped when letter spacing grows</title>
<style>
  body { color: #111111; background: #ffffff; font-size: 16px; }
  /* 13 monospace characters (7.8em) fit into 8em on one line; with 0.12em
     letter spacing and 0.16em word spacing they no longer do. */
  #chip { display: inline-block; width: 8em; white-space: nowrap; overflow: hidden;
          font-family: monospace; font-size: 16px; line-height: 2; vertical-align: top; }
</style>
</head>
<body>
<header>
  <a href="#main" style="display: inline-block; min-width: 44px; min-height: 44px; line-height: 44px; padding: 0 8px">Skip to main content</a>
  <p>Shop</p>
  <nav aria-label="Main"><a href="#main" aria-current="page" style="display: inline-block; min-width: 44px; min-height: 44px; line-height: 44px; padding: 0 8px">Overview</a></nav>
</header>
<main id="main">
  <h1>Garden chairs</h1>
  <p><span id="chip">Add to basket</span></p>
</main>
<footer><p>Footer text</p></footer>
</body>
</html>

Passing example

The check reports nothing here. Corpus case visual_text_spacing_ok. The page may contain further findings for other rules.

visual_text_spacing_ok.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Containers that keep their text at larger spacing</title>
<style>
  body { color: #111111; background: #ffffff; font-size: 16px; }
  /* Grows with its content. */
  #badge { min-height: 20px; line-height: 1.2; border: 1px solid #111111; padding: 0 4px; }
  /* Threshold: exactly one line at line-height 1.5 (24px) still fits. */
  #fit { height: 24px; line-height: 1.2; overflow: hidden; }
  /* Already cut off before any spacing change: not caused by spacing. */
  #preclipped { height: 10px; overflow: hidden; }
  /* Dynamic: fixed height removed by a script after load. */
  #late { height: 20px; line-height: 1.2; overflow: hidden; }
</style>
</head>
<body>
<header>
  <a href="#main" style="display: inline-block; min-width: 44px; min-height: 44px; line-height: 44px; padding: 0 8px">Skip to main content</a>
  <p>Shop</p>
  <nav aria-label="Main"><a href="#main" aria-current="page" style="display: inline-block; min-width: 44px; min-height: 44px; line-height: 44px; padding: 0 8px">Overview</a></nav>
</header>
<main id="main">
  <h1>Garden chairs</h1>
  <div id="badge">Free delivery on all orders</div>
  <div id="fit">In stock</div>
  <div id="preclipped">Teaser text that is cut by design and expands on click.</div>
  <div id="late">Assembly takes ten minutes</div>
</main>
<footer><p>Footer text</p></footer>
<script>
  window.addEventListener('load', function () {
    document.getElementById('late').style.height = 'auto';
  });
</script>
</body>
</html>

This page is generated from the rule catalogue and the rule contracts; see therule overview for how the outcome classes are derived.