Custom Focus Indicators with CSS Variables

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 #

Buttons with outlines on different background colors.

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:

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.

A round button with a square black outline around it.

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.

See the Pen Accessible focus ring styles with CSS variables by Matsuko Friedland (@missmatsuko) on CodePen.

Prev
CKEditor Plugin Released
Accessibility Home
Next
Designing Custom Focus Indicators