Search topics
Focus rings too thin or faint to spot
A 1-pixel, pale blue outline technically shows focus, but it is too small and too close to the page colour to find at a glance.
The problem
People with low vision can't find a focus ring that is a pale hairline.
Tab through a row of blue buttons on a white page, then through the same buttons on a dark navy banner. Each button gets a focus ring, so focus is technically visible. But the ring is a single pixel of pale blue. On the white page it almost disappears; on the banner it shows, but as a hairline you have to look for.
Success criterion 2.4.13 Focus Appearance (AAA) asks two things of an indicator the author has styled. It must cover at least the area of a 2 CSS pixel thick ring around the unfocused control. And the pixels that change must have at least 3:1 contrast between their focused and unfocused colours. The ring here is 1 pixel thick, so it fails the area test on every surface. On the white page, #a8c7fa against #ffffff is 1.72:1, so it fails the contrast test too.
This is a stricter test than 2.4.7, which only asks that focus be visible, and than 1.4.11, which asks for 3:1 against adjacent colours. The 2.4.13 contrast is a change of state: compare each pixel with what it was before focus.
Anyone with a dim or glary display is affected too.
2 of 10 groups affected
- No vision (not affected)
- Low vision (affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (affected)
- Reach, strength (not affected)
- Cognitive (not affected)
- Seizures (not affected)
- Limited vision People with low vision and people using magnification who only see part of the screen struggle to spot a hairline ring. Older users with reduced contrast sensitivity are affected even with corrected vision.
- Limited manipulation Keyboard users who look away and back need to find their place again quickly, and a hairline ring makes that slow.
Most scanners only check that focus changes something, which this ring does. Measuring the 2.4.13 area needs the control's perimeter and the indicator's thickness; measuring its contrast needs the before and after colours of the same pixels, on each surface. Generated code tends to copy a framework's thin default ring, or add box-shadow alone, which forced colors removes.
Try it
Press Tab and try to spot the focused button.
Press Tab to move through the buttons on the white page and the navy banner.
Broken Can you fix this?
A recreated demo. The broken version is intentionally inaccessible.
The fix
Draw the indicator at least 2px thick, with 3:1 between its focused and unfocused colours.
- 1The indicator is at least as large as a 2px ring around the control.
- 2Its changed pixels have 3:1 against what they replace, on every surface.
- 3An outline stays in forced colors, even when the main cue is a shadow or a fill.
.brand-button:focus-visible { outline: 1px solid #a8c7fa; outline-offset: 2px;}The ring is half the required thickness, and on a white page its pale blue is 1.72:1 against the white it replaces.
The ring is 2 pixels thick and sits outside the button, so its perimeter is larger than the button's and its area is more than enough. On the white page, #1a5fb4 replaces white at 6.29:1; on the banner, white replaces #0b2545 at 15.39:1. This holds only on the surfaces you have set a colour for: each new background needs its own check and, often, its own rule.
Each of the three passes 2.4.13. The ring per surface matches the brand closely but needs a colour and a check for every background. The two-tone ring needs one rule for any surface, including user themes and editor-chosen colours, and looks heavier. The fill change suits designs that don't want a ring, but every button style needs its own pair of colours, and the focused state must not look like the hover or pressed state. Choose by how many surfaces your buttons sit on and how much the design can change.
The 2-pixel rule is an area, not a stroke width. An outline outside the control has a longer perimeter than the control, so 2 pixels is enough. An inset indicator, drawn inside the edge, has a shorter perimeter and needs to be thicker to cover the same area. A ring with gaps, dashes or rounded corners also covers less; measure it rather than assuming.
Only the pixels that change count. A ring that is half on the button and half on the page needs 3:1 against each colour it replaces. A grey ring that differs from the page by 3:1 but sits on a grey card may not.
overflow: hidden on a parent can cut off part of an outside ring. Leave space around controls, or use outline-offset with a negative value and a thicker ring. The criterion's exception covers focus indicators that the browser draws and the author has not changed. Relying on the browser default is allowed, but browsers draw different rings, and many sites override them anyway.
Put the ring in a design token or a shared component style, so a theme change cannot quietly thin it again.
Verify the fix
5 checks, no mouse.
Test with: Contrast measurement, Keyboard, Zoom, Forced colors
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the shared theme or component styles change.
Limits
2.4.13 is a AAA criterion, so most conformance targets don't require it. It is still the clearest test of whether focus is easy to see, and a ring that passes it also passes 2.4.7 and the focus part of 1.4.11. The colours here are examples; measure your own. Test the complete journey on your real surfaces.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.