Accessibility · Perception

Which Boundary Counts for Non-Text Contrast and Focus Indicators

How the 3:1 requirement applies to component edges, icons, and focus rings, why the measured pair is the two colors on either side of a boundary, and how state changes are evaluated separately.

Text contrast has a clear subject: the ink and the paper behind it. Interface contrast does not. A button is a rectangle with a border, a fill, a label, and possibly an icon, and each of those has a different neighbor. The 3:1 requirement for non-text content is not a statement about how dark a component is; it is a statement about the difference across a specific edge, and identifying that edge is most of the work.

The measured pair is a boundary, not a component

WCAG’s non-text contrast criterion applies to two categories: visual information required to identify a user interface component and its state, and parts of graphics required to understand the content. In both cases the comparison is between adjacent colors. For a component, the adjacent color on the outside is whatever surface the component sits on; the adjacent color on the inside is the component’s fill. A 1 CSS pixel border must therefore differ from both by at least 3:1, or the outline disappears into one side.

This produces a failure that looks like a styling preference rather than a defect. A text input with a light gray border on a white page, filled white, has a boundary that is a light gray line between two whites. Whether the border meets 3:1 against white is a single computation, and if it does not, the field’s extent is invisible to anyone who cannot resolve that small difference. The label may still pass at 4.5:1, so the form looks compliant in a checker that only examines text.

Filling the field with a tint is an alternative that satisfies the same requirement by a different edge. If the fill differs from the page by 3:1, the rectangle is identifiable without any border, because the boundary is now the fill against the page. Many design systems use exactly this: a neutral fill, no stroke, and the boundary carries the contrast. The cost is that a fill-based boundary cannot indicate state as precisely as a stroke can, since changing the fill changes the whole area.

The criterion carries explicit exceptions. Components whose appearance is entirely determined by the user agent and not modified by the author are exempt, which covers unstyled native form controls. Inactive or disabled components are exempt, on the reasoning that a disabled control is not expected to be perceived as operable. Purely decorative graphics are exempt because they are not required to understand anything.

Icons, chart lines, and the objects that carry meaning

Graphical objects follow the same 3:1 rule when they are the only carrier of information. A line chart whose series are distinguished only by line color requires each line to reach 3:1 against the plot background, and the lines against each other are a separate problem handled by redundant encoding beyond hue. A meaningful icon in a toolbar, drawn as a 1 px outline, is a graphical object and its stroke is the boundary.

The interesting cases are where the graphic is a texture rather than an outline. A pie chart whose slices are adjacent to each other has boundaries between slices as well as between each slice and the background, and a compliant chart usually solves this with a 1 px separator stroke in the background color rather than by forcing every pair of slice colors apart. The separator is a graphic element too, but it is a gap, and gaps in the same color as the page are how adjacent filled regions stay distinguishable without satisfying pairwise contrast.

Non-text elements that are redundant with text are exempt in practice, which is why a decorative chevron next to the word “expand” need not meet 3:1. The exemption is about necessity, not about size: a tiny graphic that is the only indication of state is held to the same threshold as a large one, and a large decorative flourish is not held to it at all.

Focus: two different measurements

Focus visibility splits into two questions that are often conflated. The first is whether an indicator exists at all and is not suppressed by outline: none on a control that still receives keyboard focus. The second is whether the indicator is perceptible, which is where contrast enters.

WCAG 2.2’s focus appearance criterion formalises the second question with two independent requirements. The indicator must enclose an area at least as large as a 2 CSS pixel thick perimeter of the component, and the contrast between the indicator and the same pixels in the unfocused state must be at least 3:1. The second part is a change of contrast, not a contrast ratio against the background. A blue ring on a blue button can be 4.5:1 against the page and still fail, because in the unfocused state those pixels were the button’s own blue border.

That distinction matters for implementations that add a ring without removing anything. An inset ring drawn just inside the component’s existing border replaces the border pixels with ring pixels, so the change is measured at those pixels. An outset ring drawn outside the component replaces page pixels, so the change is measured there, which is usually the easier comparison because the page is uniform.

/* Two rings: the inner one guarantees contrast on light surfaces,
   the outer one on dark ones, without knowing the background color. */
:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: 2px;
  box-shadow: 0 0 0 4px #000000;
}

The double-ring pattern exists because a single ring color cannot be guaranteed to differ from an arbitrary background by 3:1. A white ring fails on white, a black ring fails on black, and components are routinely placed on both within one page. Two concentric rings of opposite polarity mean that at least one of them always contrasts with whatever is behind it, and the pair also contrasts with each other, so the indicator’s shape survives.

A single ring can still work if the component’s own surface is bounded. An inset ring of one polarity inside a fill of the other polarity is measurable against the fill, and the fill is under author control. This is why inset indicators are common in dense interfaces where an outset ring would overlap neighbouring controls.

Where indicators get clipped or lost

The mechanical failure modes are layout failures more than color failures. A ring drawn with outline-offset extends outside the element’s border box, and any ancestor with overflow: hidden will crop it. The same applies to rings on elements inside a scroll container: the ring at the leading edge is drawn in the clipped region. Containers that scroll horizontally are the usual offenders, since the ring on the first or last item lands exactly where the clip is.

Stacking contexts cause the opposite problem. A ring drawn behind a sticky header or a fixed footer is present in the DOM, computes a valid contrast ratio, and is invisible because another layer paints over it. Automated checks that read computed styles see nothing wrong.

Very thin indicators degrade differently. A 1 CSS pixel ring at a non-integer device pixel ratio is rendered across a fractional number of physical pixels, and antialiasing distributes the ring color over two or three rows of pixels at partial opacity. The computed color is correct; the perceived color is a blend toward the background, so the effective contrast is lower than the ratio suggests. On a 1.5× display, a 1 px ring becomes 1.5 physical pixels and the trailing half is blended. The focus appearance criterion’s 2 px perimeter area exists partly to push implementations away from hairlines for this reason.

States beyond focus

The same boundary logic applies to hover, pressed, selected, and error states, and the requirement is on the information that identifies the state. A selected tab that differs from unselected tabs only by a fill that is 1.2:1 away from the page conveys selection through a difference most people will not see. The usual fix is a second channel: an underline, a weight change, or an indicator bar, any of which can carry 3:1 on its own.

Error states are a special case because the conventional red border often fails against a white fill and the message text carries the actual information. When the border is the only signal, the border is the graphical object and must reach 3:1 against the fill and the page. The palette question is the same one that governs choosing colors that survive a range of contrast settings, where the author’s colors may be replaced entirely.

References

  1. Web Content Accessibility Guidelines (WCAG) 2.2 — W3C
  2. Understanding Success Criterion 1.4.11: Non-text Contrast — W3C WAI
  3. Understanding Success Criterion 2.4.13: Focus Appearance — W3C WAI