Field Notes

Twenty-four pixels is a smaller promise than it sounds

WCAG 2.2 asks for pointer targets of 24 by 24 CSS pixels. The spacing exception means a row of 18 px icons can pass and a row of 24 px icons can be hard to hit. Here is the rule, the circle, and the five exceptions, drawn.

Published

  • target size
  • pointer
  • wcag 2.2
  • layout

A 24 by 24 pixel square is about the size of the letter "M" at the font size of this sentence, doubled. That is what success criterion 2.5.8, Target Size (Minimum), asks for. It sounds like a floor under every button. It is smaller than that. Most of the rule lives in its exceptions, and the first exception is a circle.

The sentence

The size of the target for pointer inputs is at least 24 by 24 CSS pixels. "CSS pixels" means the pixels the page is laid out in, not the pixels of the screen. A 24 px button is 24 px at any zoom level and on any display density. A "target" is the area that responds to a click or a tap, which is usually the box of the button or link, including its padding.

That is the whole rule. Everything else is an exception.

The circle

A target smaller than 24 by 24 still passes when it has room around it. The test: draw a circle 24 px across, centred on the target. If that circle does not touch any other target, and does not overlap the circle of any other small target, the target passes by spacing.

Three rows of icon buttons and how the 24 pixel circle decides each one Row one: three 24 pixel squares side by side, each labelled pass by size, no circle needed. Row two: three 18 pixel squares with 6 pixels between them; each has a dashed circle 24 pixels across on its centre, and the circles touch but do not overlap, labelled pass by spacing. Row three: three 16 pixel squares touching each other; their circles overlap heavily, labelled fail. 24 px, touching Pass by size. The circle is not needed. ✓ 3 of 3 18 px, 6 px apart Pass by spacing. Each circle has its space. ✓ 3 of 3 16 px, touching Fail. The circles overlap. ✕ 0 of 3
Drawn at twice life size. The middle row has no 24 px target in it and passes. The bottom row fails as a group: each icon is small, and each circle lands on its neighbours.

Two things follow from the circle that surprise people.

  • A row of small icons with generous gaps passes. The icons in the middle row above are 18 px. Nothing in that row is 24 px, and every one passes.
  • The same icons with 2 px gaps fail together. Nothing about any one icon changed. What changed is that the circles now meet.

So the rule is not "every button is 24 px". It is "every button is 24 px, or has 24 px of its own space". The lab draws the circle on every small control so you can watch that line move.

The other four exceptions

Spacing is one of five. The others:

Exception What it means Example
Equivalent The same function is available through another target on the same page that does meet the size A 16 px close icon in a toast, plus a full-size Close button in the dialog it opened
Inline The target is a link inside a sentence or block of text, and its size is set by the line height A link in a paragraph
User agent control The browser draws the target and the author did not change its size A native checkbox, a native select arrow
Essential The size is set by a rule outside the page, or a bigger target would change the information being shown Pins on a map where moving them would change what the map says

The inline exception covers more than it seems to. A link in running text is exempt even when it is one word long and 16 px tall. The reason is that you cannot make it bigger without breaking the line. The exception does not cover links styled as buttons, or a list of links where each is on its own line and could be padded.

What does not count

  • Making a target bigger with padding counts. The padding is part of the box.
  • Making it bigger with margin does not. Margin is outside the box and does not respond to a click. It does count toward spacing, though, because it pushes the neighbours' circles away.
  • A transparent hit area behind a small visible icon counts, as long as it responds to the pointer. The lab measures the box that responds, not the pixels you can see.
  • Overlapping targets do not pass by being large. Two controls on the same pixels cannot both be hit. The lab reports that as its own kind of fail.

Measuring it

Open the browser's inspector, hover a control, and read the box size. Then look at its neighbours. If the control is under 24 in either dimension, measure from its centre to the nearest edge of the next control. That distance needs to be at least 12 px. If the next control is also under 24, the two centres need to be at least 24 px apart.

Measure on whole pixels. Browsers lay out on whole CSS pixels in most cases, and a fix that works out to exactly 24.0 can land at 23.5 after rounding. Give it half a pixel of room.

Try it

The Target Size and Spacing lab puts real buttons at their real size in a toolbar you can resize. Start with the share bar, which passes by spacing. Set the gap to 2 and read the verdicts change. Then drag one icon away from the others and watch its circle clear.

Sources

  • w3.org, Understanding Success Criterion 2.5.8: Target Size (Minimum), the spacing exception and the four others
  • w3.org, Understanding Success Criterion 2.5.5: Target Size (Enhanced), the 44 px level

Open the companion lab

  • When the toolbar will not fit

    Five icons, a narrow bar, and a 24 px rule that cannot be met as laid out. Adding height does not fix it. Wrapping does. An equal split of the width can leave every icon one pixel short. Here is the order to try fixes in, and when to stop.

  • Tab order is a promise the DOM makes

    The Tab key follows the HTML, not the layout. CSS cannot change that order, a positive tabindex hijacks it, and aria-hidden does not remove a stop. One real walk found 162 stops where a list of the markup said 64. Here is why, and how to check.

  • The sticky header that eats your focus

    Shift+Tab back up a form and the field you land on slides under the sticky header. The browser scrolled just far enough, and just far enough is behind the bar. WCAG 2.2 calls it focus not obscured. One CSS property fixes it.

Spotted something this note gets wrong?

Corrections and better examples are the best kind of message.

Send a correction