auditmysitev2.0.2

Insufficient click target size (AAA)

targets/size-enhanced

WCAG success criterion
2.5.5 (level AAA)
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, Navigation & Operation
Default severity
medium
axe-core rule
target-size

Why we flag this

Users with hand tremors or on mobile devices easily tap the wrong elements.

Links, buttons or form controls dimensioned too small in CSS.

What the rule checks

Scope. The same pointer targets as targets/size.

Expectation. needs_review once per target smaller than 44 x 44 CSS px, without a spacing exception: 43 px fails, 44 px passes. Same exceptions as targets/size (inline, label, visible same-destination equivalent of 44 px, not rendered). A target that already fails 2.5.8 is reported once, under targets/size, not a second time here.

Source. WCAG 2.2 SC 2.5.5 Target Size (Enhanced): 44 x 44 CSS px, exceptions Equivalent, Inline, User agent control, Essential (no spacing exception)

Detection: shared; needs dom, geometry, computed_style.

Failing example

The check flags this for review. Corpus case target_size_hidden_neighbours, element a#beside-details. The page may contain further findings for other rules.

target_size_hidden_neighbours.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Target size hidden-neighbour corpus case</title>
    <style>
        .row { display: flex; gap: 0; margin: 48px 0; align-items: flex-start; }
        .row a { display: block; flex: none; width: 16px; height: 16px; overflow: hidden; font-size: 10px; line-height: 16px; }
        .row a.n { width: 48px; height: 48px; }
        details, summary { display: block; flex: none; margin: 0; padding: 0; }
        summary { width: 0; height: 0; overflow: hidden; list-style: none; }
    </style>
</head>
<body>
    <main>
        <h1>Undersized links next to targets that cannot be seen or clicked (#705)</h1>
        <!-- Each row: a 16x16 link and, directly to its right, a 48x48 neighbour. The 24 px circle
             around the small link touches the neighbour, so a visible neighbour makes it fail.
             The neighbours meet the size themselves, so none of them spends the rule's cap. -->

        <!-- violation (control): the neighbour is visible and clickable -->
        <div class="row">
            <a id="control" href="/control">C</a>
            <a class="n" href="/control-next">N</a>
        </div>

        <!-- pass: the neighbour sits in a closed <details>; Chrome keeps its box but hides it
             via ::details-content { content-visibility: hidden } (geographia.eu) -->
        <div class="row">
            <a id="beside-details" href="/details">D</a>
            <details class="more">
                <summary>More</summary>
                <a class="n" href="/details-a">A</a>
            </details>
        </div>

        <!-- pass: the neighbour is inert -->
        <div class="row">
            <a id="beside-inert" href="/inert">I</a>
            <div inert><a class="n" href="/inert-next">N</a></div>
        </div>

        <!-- pass: the neighbour has pointer-events: none -->
        <div class="row">
            <a id="beside-no-pointer" href="/no-pointer">P</a>
            <a class="n" href="/no-pointer-next" style="pointer-events: none">N</a>
        </div>
    </main>
</body>
</html>

Passing example

The check reports nothing here. Corpus case target_size_animation, element a#intro. The page may contain further findings for other rules.

target_size_animation.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Target size during animation corpus case</title>
    <style>
        .row { display: flex; gap: 4px; margin: 48px 0; align-items: flex-start; }
        .row a { display: block; flex: none; height: 48px; overflow: hidden; white-space: nowrap; line-height: 48px; }
        .big { width: 48px; }
        /* A logo intro that grows from nothing, like geographia.eu's module name (#706). */
        @keyframes grow { from { width: 0; } to { width: 120px; } }
        #intro { width: 120px; animation: grow 1s ease-in; }
        @keyframes grow-slow { from { width: 12px; } to { width: 120px; } }
        #slow { width: 120px; animation: grow-slow 3600s linear; }
        @keyframes spin { to { transform: rotate(360deg); } }
        .spinner { width: 16px; height: 16px; border: 2px solid; animation: spin 1s linear infinite; }
    </style>
</head>
<body>
    <main>
        <h1>Targets measured while they animate (#706)</h1>
        <!-- An infinite animation never settles; it must not hold up or suppress anything. -->
        <div class="spinner" aria-hidden="true"></div>

        <!-- pass: grows from 0 to 120x48 over 1 s; the audit waits for the animation to finish
             and measures the final size. Measured mid-animation it would be undersized, with a
             neighbour 4 px away. -->
        <div class="row">
            <a id="intro" href="/intro">Atmosphere</a>
            <a class="big" href="/intro-next">Next</a>
        </div>

        <!-- pass (not failed, needs review): still growing after the settle budget, so its size is
             reported as not measured instead of as a violation -->
        <div class="row">
            <a id="slow" href="/slow">Slow intro</a>
            <a class="big" href="/slow-next">Next</a>
        </div>
    </main>
</body>
</html>

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