We’ve been working to improve focus styles within Craft’s control panel lately, and will be sharing what we’re learning along the way. Here’s the third and final post of a three-part series on visible focus indicators.
Introduction
This post will present a method of styling an offset outline type focus indicator using box-shadow
and CSS variables.
This method will meet the following criteria:
- Meets WCAG 2.1 AA success criteria for visible focus indicators
- Does not interfere with Windows high contrast mode
- Supports various background colors
- Supported in modern browsers (the method described in this post is supported in browsers that support CSS variables)
Skip to the demo of the final result or read on for a walkthrough of how this was achieved.
Why use box-shadow
?
There are many ways to add an outline around an element with CSS. The simplest ways are probably using outline
or border
, but box-shadow
is often used to style focus indicators. It's a bit hacky, but using box-shadow
currently offers several benefits that often make it the preferred method of adding an outline.
outline
The outline
property is used for default focus indicators in browsers. It offers customizability in color, style, width, and offset (and radius in Firefox). outline
isn't usually used for styling, so there's less chance of styling conflicts.
This is the most sensible property to use to add outline styles, as long as the styling limitations are acceptable. For one thing, it isn't possible to create a focus outline with multiple colors. Additionally, the outline's shape won't necessarily match the element, which might look a little strange in some cases. For example, a round button will still have a square outline.
border
border
offers customizability in color, style, width, and radius.
As with outline
, multiple colors can't be used. The main drawback to using border
is that it takes up space, which means the element might be misaligned, or shift when it's focused.
pseudo-elements
It would be possible to apply multiple outlines or borders on an element by styling their pseudo-elements (e.g. :before
and :after
). Unfortunately, not all focusable elements can have pseudo-elements, so this is not a reliable method.
box-shadow
box-shadow
is not the most obvious method of applying an outline style, but it has several benefits: it doesn't take up space, it matches the element's shape, and it can take multiple colors.
There isn't a way to set the distance between an element and its box-shadow, but it can be faked by adding a box-shadow of the same color as the background the element is on. CSS variables make this easier to accomplish.
Walkthrough
We'll start by setting the initial values for the focus ring color and the background color.
:root {
--focus-ring-color: #0e44af;
--background-color: #fff;
}
Next, since we'll be adding our own focus styles with box-shadow
, we'll want to hide the browser's default outline
focus style. Instead of completely removing the outline by setting outline: none
, we'll set outline-color: transparent
. This will hide the outline while ensuring it's still visible in Windows high contrast mode.
Sarah Higley has an excellent blog post with this and other tips on Windows high contrast mode.
:focus {
outline-color: transparent;
}
We're also going to set the outline-style
to solid
. This is to ensure the default browser focus style in Edge, which has 2 colors, doesn't show.
:focus {
outline-color: transparent;
outline-style: solid;
}
Now we'll add our box-shadow
outline. This style leaves a gap around the focus element with the same color as the last set background color, and a focus ring with the last set focus ring color.
As long as the focus ring color has sufficient contrast against the background color, this will meet the focus visible success criteria.
:focus {
outline-style: solid;
outline-color: transparent;
box-shadow: 0 0 0 2px var(--background-color),
0 0 0 5px var(--focus-ring-color);
}
Finally, we'll add some different background colors. The box-shadow's gap color will always match the focused element's background color since we're setting the background color by modifying the --background-color
CSS variable.
.bg-color {
background-color: var(--background-color);
}
.bg-color--vanilla {
--background-color: #fff8e9;
}
.bg-color--strawberry {
--background-color: #ffeae8;
}
.bg-color--chocolate {
--background-color: #ecdad4;
}
Result
Here's a CodePen demo with the final result! You can test out the focus styles by tabbing through the buttons.