The focus indicator must be discernible on every background
Aliases: focus ring · focus-visible · focus visibility
What it is
Wherever the keyboard is sitting, that control’s background must still show it. A 2 px brand-blue stroke that is clear on a white page dissolves on a primary blue button or a photographic hero. A focus indicator has to separate from adjacent pixels on light fills, dark fills, brand blocks, images, and striped table rows. That is not “is the control’s resting border dark enough” (non-text contrast). It is whether this focus mark is still there on the ground it actually occupies.
Why it happens
A focus mark is contrast between the mark color and adjacent pixels: control fill, page ground, sometimes a photo. A single-hue ring cannot cover all of those grounds — blue on a blue button tends toward ratio 1. A two-tone ring (outer white, inner black, or the reverse) or an inner-plus-outer stroke uses two opposite luminance gaps so at least one holds on the current ground.
Width takes part in discernibility. A 1 px antialiased ring smears into the fill on high-DPI displays and under low-vision magnification. :focus-visible decides when to paint, not whether the paint is enough. Dark mode and high contrast swap the ground; a ring tuned only on a light mock fails on the inverted page. A hover that darkens fill is a pointer-state contrast problem and is not a substitute for a keyboard focus mark.
Studying it
Keyboard-only, screenshot focus on every class of background: light page, dark page, primary button, ghost button, a text link on an image, a selected table row. Measure the ring’s outer edge against adjacent pixels. Repeat with system “increase contrast / forced colors.”
Independent variables: indicator style (thin single-hue ring / two-tone / inner stroke), background type. Dependent variables: whether an observer can point at focus, ring-to-ground contrast, backgrounds where it is lost.
Do not substitute a mouse click: click may take :focus and hide it, which is not the Tab state.
Where it stops holding
Hiding focus after pointer activation and showing it after keyboard activation is a legitimate split, provided the keyboard ring remains discernible on every ground. Custom controls with no native outline make this stricter; the browser will not draw a fallback. Focus covered by sticky chrome is a different kind of “cannot see”; the ring itself may be bright enough. Self-drawn focus inside a canvas or map must be painted in that layer; a CSS ring never reaches those pixels.
Applying it
- Use two tones or inner and outer strokes, not one brand color tuned only on white.
- Give the ring enough thickness. Do not rely on 1 px antialiasing.
- Keep acceptance frames of focus on the primary button, the inverse button, and a link on an image — not only on a light gray page.
- Verify: hide the pointer, Tab through the page. Any stop you have to guess is a defect in the indicator or in that ground. Replay the path in dark mode and high contrast; lost stops are defects.
Related
- Same group: J2.06.2 Removing the default outline requires a replacement · J2.06.3 Focus must not be covered by sticky or fixed chrome
- Nearby: J2.10 Non-text Contrast · J3.01 Keyboard Access · J2.15 Dark Mode and High Contrast Compatibility
- Search terms:
focus indicator·focus-visible·two-tone focus ring