Focus Styling
Focus states are used by keyboard users to know what interactive element they can currently manipulate. They are usually styled with
Focus Styling For Keyboard Users Only
When I am auditing a website for accessibility issues for the first time, lack of focus indicators is usually one of the first things I see. This is usually because a lot of designers and/or developers will think that focus indicators look ugly and will put in the following CSS to get rid of them:
This is a bad idea. Keyboard users need focus states need these focus indicators to know what interactive element currently has focus. "But VoiceOver has it's own focus indicator!" is what I hear some of you say. Not everyone who uses a keyboard uses VoiceOver. You absolutely need a visible focus indicator on all your interactive elements in order to pass WCAG 2.4.7.
What you can do is make focus indicators only appear for keyboard users? This can be done using the
:focus-visible
CSS pseudo-class. Here is how the Enable site codes them globally using TPGI's excellent method to use
:focus-visible
while ensuring browsers that don't support it fallback to using :focus
gracefully:
Is it just keyboard users that will see focus states styled with focus-visible
? Kind of, but there are a
few subtleties. Andy Adams has written a great article for CSS Tricks about
:focus-visible that really goes into detail.
Increase Hit Areas Inside Focusable Elements
If you use a keyboard to navigate through the main navigation, you will notice the clickable hit-area of the top level navigation items are a lot bigger than they actually take up in the layout:

We increased the hit area to conform to WCAG 2.5.5: Target Size (we made it larger than 44 pixels x 44 pixels). Even though this is a AAA requirement, it is so easiy to implement by increasing the padding and componsating visually with an equivalent negative margin, so why just conform to WCAG 2.5.8: Target Size (Minimum). (which only asks 24 pixels x 24 pixels)?
I encourage everyone reading this to implement this on all the websites they code. From a UX perspective, it just makes it easier for everyone to use the websites you code.
Issues with CSS Transitions and CSS outline in Safari
On a few projects, I have noticed that Safari focus states don't appear correctly when the element that is focused has the following CSS applied to it:
The above CSS can mess up Safari focus states: they may appear cut off or may not appear at all in Safari, while they
may appear fine in other web browsers. The correct way to fix this is to never use
transition: all
in your CSS. Using all
. There are many reasons why you should
never use not use the all
keyword for transitions (in this case, because of unwanted side-effects, but
also for performance reasons). Philipp Nowinski has written a great write-up on why you shouldn't use the 'all'
keyword in CSS transitions, and I suggest all developers read this.
If removing the all
transition code will cause problems in your project, you can use the following hack
to fix the code in Safari:
Note that it is much better to remove the all
keyword and just transtition what you need
instead. This solution should only be a band-aid solution until you can fix the issue properly.
Don't Forget Windows High Contrast Mode Users.
Sometimes, you will want to style focus states without the CSSoutline
property. If you do this, but
instead of using outline: none
to remove the default focus ring, developers should use outline with the
transparent
colour:
Guaranteed Contrast on Focus Rings, Regardless of Background
If you don't know what colour background your focus rings will be on top of, there is a simple way of ensuring your
focus rings will follow contrast rules: using outline
and box-shadow
at the same time.
Here is an example you can tab into to see this combo in action:
This is a dummy link This is a dummy link This is a dummy link This is a dummy link This is a dummy link This is a dummy link This is a dummy link
If you are using a mobile device, here are some screenshots you can look at to show how it looks:
Focus State | Screenshot |
---|---|
No Element is Focused |
![]() |
Focus on Lighter Area of Gradient |
![]() |
Focus on Darker Area of Gradient |
![]() |
Here is the markup that implements the double focus ring. Notice the use of both outline
and box-shadow
to create this effect (the box-shadow offsets must be greater than the outline thickness in order for this to work):