Focus Styling
Focus states are used by keyboard users to know what interactive element they can currently manipulate. They are easily
styled with the outline
CSS property and the :focus
and :focus-visible
pseudo-classes.
Unfortunately, many designers hate them and try to get focus-styles removed from a website. This page discussed
in detail why this should be avoided and how to keep designers happy by having focus-styles appear for keyboard users only.
Focus Styling For Keyboard Users Only
When I am auditing a website for accessibility issues for the first time, a 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:
*:focus { outline: none; }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 its 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 can you do to 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 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 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 easy to implement by increasing the padding and compensating 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:
a { transition: all 0.3s ease-in-out; }
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 transition 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
color:
button.special-style:focus { outline: transparent 2px solid; border-bottom: 2px solid #00f; }
Guaranteed Contrast on Focus Rings, Regardless of Background
If you don't know what color 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):