Focus Appearance thoughts

I think it is fair to say that some folks aren’t very happy with the focus-appearance criterion proposed in WCAG 2.2. Hidde thought it adds too much complexity, and Eric didn’t rate it.

I think everyone sees the value of having good focus indicators, so I’m taking the comments as a challenge to provide the easiest possible way of explaining the criterion and how to test it. Eric wants to do a good explanation in an hour, I’m going to aim for 15 minutes.

Below is a video of a presentation on focus appearance, below that is the text equivalent.

You can also view the video on Youtube if the basic video player above doesn’t work well enough.

Focus Visibility Factors

There are three main things that appear to affect the visibility of a focus indicator, with poor examples shown as the middle item of each:

  1. The change of colour (contrast) from the original colour. Without that it can fade from sight.
    Three dark buttons, the centre one has a light grey outline against a white background.
  2. The size and thickness of the change, otherwise it can be too small to discern.
    Three light buttons, the centre one has a thin border on the left side only.
  3. The difference of colour (contrast) from the surrounding colours. Without that it can merge into another area of colour.
    Three dark buttons, the centre one has a thin outline of the same colour, making it a tiny, tiny by larger than the other buttons.

Without capturing each of these factors in the criterion, it would allow invisible (or poorly visible) indicators.

“Safe” indicators

If you just want to be sure you are passing, sod the detail, these are some safe indicators:

  • A contrasting line (against the background) slightly separated from the button.
  • A thick block inside (or out) of the button that contrasts.
  • A thick line (2px or more) around the button.

That last one doesn’t have ‘adjacent contrast’, but when you’re adding a 2px thick indicator, the button is getting larger by 4px in height and width. That just crosses over the baseline of visibility we were aiming for.

The SC text

The full criterion text is in the draft spec of WCAG 2.2. It is in three parts:

  1. The easy(er) to understand metrics.
  2. The flexible, but harder to understand metrics.
  3. The exceptions.

The easier to understand bullets say the indicator needs to enclose the component, have a change of contrast (at least 3:1), and adjacent contrast.

If you have a component with a light background, a simple dark outline will work. If the component has a dark background, you’ll need to separate it slightly from the component.

A light button with a dark outline, and a dark button with a separated dark outline.

If that’s a reasonable indicator for your site, that’s it, job done.

However, if you wish to use a different form of indicator, you’ll need to read the second part.

Area calculations

The first bullet contains two area calculations, you can use either, the first is:

An area of the focus indicator meets all the following:

  • is at least as large as the area of a 1 CSS pixel thick perimeter of the unfocused component or sub-component

It is asking for an area that is proportional to the component, in this case the perimeter. Imagine a 1px line around it, what area is that?

A light button with a dark outline, the outline has been copied separately, showing the 4 lines separately.

For example, a 25 by 100px button requires an indicator area of 25+25+100+100 = 250px.

Technically we need to take off 4px for the corners as they overlap, so it is 246px. However, if you are relying on 4 pixels you have bigger problems. If it is that close, pick a different indicator!

The second size metric you can use is:

at least as large as a 4 CSS pixel thick line along the shortest side of the minimum bounding box of the unfocused component

This metric is useful for indicators that are quite thick, but not proportional to the length of the control. When the length of the control varies with the text, this type of indicator provides a stable area.

A light button with a thick left border. The border has been copied separately, showing the 4 short lines separately.

With the same example button, a 25 by 100px button requires an indicator area of 25 x 4 = 100px. This allows some buffer for indicators just under the perimeter metric, e.g. an inner outline.

The “minimum bounding box” aspect is useful for non-rectangular shapes which have a larger perimeter, and to simplify testing. If the shape were a star it would have a large perimeter. On the other hand, a circle actually has a smaller perimeter than the bounding box.

A cicular button with a red square drown around it.

For a circle with a diameter of 100px the perimeter = 100 x 3.14 = 314px. That is less than the 4 times shortest side metric, so a cicrular outline is probably the best approach.

Adjacent contrast OR Thickness

The last bullet of option 2 is slightly different from option 1:

has a contrast ratio of at least 3:1 against adjacent non-focus-indicator colors, or is no thinner than 2 CSS pixels.

This allows for 2px (or thicker) indicators that do not contrast with the component itself. It does not mean that it can lack change of contrast, only adjacent contrast. It allows for this type of indicator:

A dar blue button with a thick green outline.

Testing focus appearance

Easy to assess passes

There are quite a few indicators that you can see immediately when they pass.

  • 1px solid, contrasting outline
  • 3px dashed / dotted, contrasting outline
  • Contrasting change of background colour
  • Default indicator on a default (white) background

Easy to assess fails

There are quite a few indicators that you can see immediately when they don’t pass.

  • 1px solid, non-contrasting outline
  • 1px dotted outline
  • Non-contrasting change of background colour
  • Default (Edge/Chrome) indicator on dark button

Using the Browser Inspector

You can establish the size/thickness of most indicators by using the code inspector:

  1. Inspect the control
  2. Open the “:hov” selection
  3. Tick “focus”. If nothing changes on the control, try “focus-visible”.
  4. Select the “computed” tab and ensure that “Show All” (Chrome/Edge) or “Browser styles” boxes are ticked.
  5. Filter to “outline”. If that doesn’t work, try “border”, “shadow”, or “background”.

The size in CSS Pixels is reported in the “computed styles”, even if it is defined in other units in the authored CSS.

If the browser default indicator is active (not overridden by the author), you may not find the definitions, or they may not be reported accurately. If it is the default indicator and there is no change of background colour then it passes. If backgrounds have been changed, check the visual output.

Default indicators are:

  • Edge/Chrome default: 1px white outline, AND an inset 2px black outline.
  • Firefox: For buttons/controls – 2px medium blue border with light blue halo.
    For links – 1px blue outline.
  • Safari: 3px blue (#8CB6FA) outline, slightly inset so it often overlaps the border of a control Doesn’t contrast with white (2.1 : 1).

Using a graphical app

If you are not familiar with CSS, you can test it visually. These are Mac based commands, but Windows has equivalents.

  • Use a standard density monitor where 1 device pixel = 1 OS pixel. (Check on
  • Check the browser is at 100% zoom.
  • Screenshot the focus indicator (shift-control-command-4 on MacOS adds it to your paste history as the latest item).
  • Use an image editing tool (e.g. Preview on MacOS, press command-n to open the image from your clipboard).
  • Zoom-in and select an area to measure.

An example of a zoomed in screenshot showing the measurement of thickness of an indicator.

Tricky examples

A couple of tricky examples I came across recently are worth working through. For example, the search input on

Two search inputs, the second has a yellow outline (on a light background) and the border appears thicker.

The additional yellow doesn’t have a sufficient “change of contrast”. However, the border gets substantially thicker, we can see from the code:

.search__input[type="search"]:focus {
  outline: 3px solid #fd0;     // yellow
  box-shadow: inset 0 0 0 2px; // additional 2px dark "border"

Although it lacks ‘adjacent’ contrast, it is 2px thick so passes.

Taking a ‘half and half’ screenshot to compare the focused / non-focused state also helps:

A black line in one half of the screenshot, then a thicker black line with a yellow outer line in the other half.

Another tricky example is using a dashed outline, which Microsoft does on their homepage navigation.

Screenshot from of the logo with a 1px dashed outline.

I started testing this in Firefox, and a 1 px dashed outline has 50% coverage of the perimeter (3 pixels ‘on’, 3 pixels ‘off’). It is not continuous, so does not pass using the option 1 bullets. The component is 55px tall by 137px wide.

Trying 4 x shortest edge, the minimum area of the indicator needs to be 55 x 4 = 220px.

The size of the indicator is (137 x 2) + (55 x 2) = 384.
Then divide by 2 due to the coverage of “dashed” indicator, so 384 / 2 = 192px.

So that was a fail, in Firefox. Not far off, but not sufficient. However, then checking in Edge (or Chrome), the dashed indicator has ~66% coverage in Edge/Chrome, so just passes!

So if you’re catering to a broad browser base, then a 1px dashed indicator is not a safe one.

A “safe” indicator would be something that passes no matter the shape of the component, such as a solid contrasting outline, or‘s approach of 4px thick underline.

With that type of indicator no calculations are needed, they will reliably pass.

6 contributions to “Focus Appearance thoughts

  1. Eric posted an update, so I’ll continue the conversation here.

    As a tester, it is not on me to chose that. I need to measure it. And if there is a difference of 4px, I need to understand that.

    I do understand there’s a difference between designing a focus indicator, and testing other people’s (potentially quite random) indicators. If an instance of an indicator is that close, there is very likely an instance (e.g. different shape) that is failing.

    What happens if a specific style does not meet the SC – even barely – in one case and does meet it in another.

    From testing sites with this SC, you tend to get a few types of indicator on a page. Once you’ve assessed an instance, it is easy to note whether the other instances pass. If the first one is on the edge, you can look straight for the worst example. Kind of like you do with testing colour contrast on a varied background.

    That’s why I was using the concept of ‘safe’ indicators, because they are reliable across scenarios.

    Would the perimeter apply only to the text height, if there was no background color?

    Yea, we went back and forth on that question. The answer is that you would default to the visuals, including the position of the indicator. If the indicator shows the component is larger than the background, that’s ok. It leads to a fairly common sense approach.

    A white button with black text whose focus style is an inverted color scheme: … there is nothing in the SC that screams that makes this pass obvious.

    We still have a balance between the size & complexity of the SC text, and where to expound on all the possibilities. As soon as you’ve seen it as an example, it is obvious from the ‘area’ aspect, but I understand it is an initial leap.

    I think our best bet is to incorporate those types of examples near the top of the understanding doc.

    I think the best case scenario is that everyone will test for the obvious scenarios and then ignore everything that is non-obvious or close enough. And that will probably be OK.

    I sort of agree, but I think/hope that failing and ‘unreliable’ indicators will get replaced with reliably visible ones.

  2. I may have mentioned this in the past but I think it bears repeating.

    Regarding the line:
    *”A thick line (2px or more) around the button….. adding a 2px thick indicator…larger by 4px…. just crosses over the baseline of visibility…..”*

    This is really only true if that button is in close proximity to other “off” buttons, such that a comparison can be made. If there is nothing to compare it to, such a subtle change is easily unnoticed. Here, because it is a very dark navy blue, any dark outlines may be subsumed into the body of the button.

    And this applies not just to visual impairments but it’s a cognitive issue as well. In fact it’s a general UX issue that applies to anyone coming to the site, who is not specifically familiar with the interface, which arguably will be most people.

    If the only changes the thickness of the border with no other change, and there’s nothing nearby to compare it, and that border change is completely symmetrical, I’d consider it an unnoticeable change in some circumstances.

    I needs something else. Size contrast has a corollary to the advice regarding color contrast, in that as far as coding data you should want something more than “just” that.

    A change in size without something to compare it to, to compare it before and after, is not a meaningful change in terms of visual recognition, particularly for somebody who is not familiar with the interface.

    This is similar to using simply gray as a way to code information, it’s only useful if it’s immediately adjacent to another grey, so that a comparison could be made. But a single patch of gray by itself can’t encode information other than perhaps between white and black, and even then it it can become ambiguous for a number of reasons.

    You can add color as in hue, as in the example, but in the case of that red, a protanope will see it near black and indistinguishable from the navy blue button.

    In the example, because the button is dark navy, and the added red line is also very dark, for many, particularly protan but also deutan, the only distinguishable change is a few percent in size.

    Because the button is already large enough to be in/at peak contrast sensitivity, for many, there’s very little change to be noticed, and something to compare to is very much needed.

    This has nothing to do with “theoretical purity” this is simply about practical and functional considerations.



  3. Hi Andy,

    All true, but it was a case of having to draw a line somewhere, and not wanting to create false positives.

    I.e. that same rule applies to the input example from, which essentially doubles the width of the input line. So the same rule of adjacent contrast applies whether it is adding to a solid button, or adding to a thin border.

    I almost added a 4th factor to the ‘what makes it visible’, which is factors that support tracking from one item to another. Most of your comment was on that (set of?) factor(s).

    However, people already complain about the complexity, so I didn’t mention it in this (aiming to be) simpler explanation.

  4. Would the perimeter apply only to the text height, if there was no background color?

    Yea, we went back and forth on that question. The answer is that you would default to the visuals, including the position of the indicator. If the indicator shows the component is larger than the background, that’s ok. It leads to a fairly common sense approach.

    So, what is the answer here? Because this is actually not one. Take this screenshot here:

    What is the shortest side? The height of the Windows logo? Or – as this is a screenshot of only the link where the logo is in – the whole height of the link? Basically: do the entire 54px of the link count as the basis of the calculation, or only the 23px of the logo height?

    Then there is the “an area” clause. This is the focused component: It’s a dashed line. Each of the small dash areas does not meet the requirements. The sum of all contrasting pixels does meet the area requirement. And I think that is what meant, but the SC language is not clear on that.

    I created a video (which is twice as long as yours – some of that runtime comes from being not really organized) where I go through this use case to figure out what needs to be done. If the small logo area is the basis, then the SC is eyeball-able in this case. If the large area is, the difference between the contrasting focus areas is just 30 pixels. watch?v=NeunNnis4FA

  5. Hi Eric,

    I thought this was the answer “you would default to the visuals, including the position of the indicator.”.

    So take your second screenshot, what are the dimensions of the focus indicator? That sits around the component. That is the last example I worked through above in the article.

    The sum of all contrasting pixels does meet the area requirement. And I think that is what meant, but the SC language is not clear on that.

    The focus indicator is the pixels that change between unfocused and focused, therefore the “area” is the sum of the pixels that meet the bullets.

    We tried other formulations than “an area”, but you end up failing good indicators, e.g. large indicators with a gradient.

  6. Oh, so the focus style is part of the component and if I increase the focus style’s visual area, I need to provide a more visible focus style. That sounds a little recursive but workable once it’s clear (which the SC really should try to do).

    Instead of “an area”, maybe “the combined area of the focus indicator that meets the following criteria is at least” or something…

Comments are closed.