
CSS Focus State
CSS Focus State ź“ė Ø
Warning
This post was written 5 years ago!
Personal opinions and technical details may have changed since writing.
One big and easy win for website accessibility is focus state. Unfortunately this is too often ignored, and worse, actively regressed. Early in my career I was guilty of:
:focus { outline: none; }
This removes the default browser style and makes keyboard navigation practically impossible. Later I would learn the error of my ways and allow the browser to do its thing. Nowadays, if a website design doesnāt consider focus state ā which is common ā Iāll take it upon myself to add it and preach the virtues.
Recent Work (in progress)
Many moons ago I build the front-end for Parts Giant. This year weāre rebuilding with a new responsive design to modernise all aspects. Accessibility is a big focus, quite literally. As an example, take these Button states. From left-to-right: default, hover, and focus:

Iāve adopted this focus style across the entire component library.
Logo states from top-to-bottom: default and focus:

The logo links to the homepage as one would expect. There is no hover effect, other than the native mouse pointer, but the focus ring is prominent.
Using the correct HTML element is just as important. The Button component is strictly reserved for <a> or <button> elements. The <details> and <summary> elements are fantastic too. The browser provides free accessibility and interactivity without any JavaScript. Our Accordion component uses these elements and adopts the focus style:

Robin Rendle on CSS-Tricks has an insightful article on the versatility of these elements.
The Card
The concept of a Card is a common design pattern youāve seen on many websites. Below is a variant of a product listing card. States from left-to-right: default, hover, and focus:

This component uses the :focus-within pseudo-class to highlight the entire card when the product link is focused. Below is a reduced code example:
<article class="Card">
<a href="/">Product name</a>
</article>
.Card:focus-within {
outline: 2px solid red;
}
.Card a:focus {
outline: none;
}
.Card a:focus,
.Card a:hover {
color: red;
}
The final trick is to make the entire card interactive. An invisible ::after pseudo-element on the link can be used to achieve that:
.Card {
position: relative;
}
.Card a::after {
content: "";
display: block;
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
Be sure to check out Inclusive Components by Heydon Pickering for a thorough take on the card pattern and many other accessible components.
Extending the Card
Another website Iāve been building has a more complex card component.

The hover state for the main article link is a subtle underline (middle example). Like before, the entire card is clickable with the pseudo-element trick.
To apply the focus state (right most example) Iām using the newer :focus-visible pseudo-class to apply an outline to the ::after pseudo-element. This appears with keyboard focus but doesnāt flash visible when clicked.
What make this component fancier is that it has multiple links inside. Alongside the article heading there are category links and a superfluous āread moreā link.

extended article component design states
All links have a subtle hover underline (far left and right in the screenshot above). Iāve added z-index: 1; so that they sit above the invisible ::after pseudo-element.
The category links are also focusable (middle example above). The āread moreā link however is not focusable. Itās redundant and only serves as visual sugar. Iāve added the tabindex="-1" and aria-hidden="true" attributes.
Stay Focused
When in doubt stick to a bold outline style. Itās common for the :hover state to be repurposed for :focus. This is better than nothing but can be too understated. Donāt forget the useful outline-offset property to improve visual spacing. I do this on my own website. My button states from left-to-right: default, hover, and focus:

Iāve recently noticed Firefox has started applying the border-radius to the outline style. I like the effect on my design but Iām not sure I want that to be default behaviour.