Focus Style for Keyboard Navigation Only
Jerome Smadja
Posted on April 25, 2019
I had the idea of this post after reading this one Designing button focus states for better usability, if you haven't read it yet, go for it.
Accessibility vs UI
Well, I didn't really want to oppose a11y to UI as a fight but couldn't come up with a better name.
Sometimes, you might want to remove the default outline the browser will provide for free. When you do that, you certainly please your designers, but you're making it hard for people who rely on assistive technologies, or keyboard navigation.
With :focus-visible
(Specs in Working Draft) you can make both sides happy. I still wouldn't recommend to remove the whole outline on :focus
on every element of your app because it can still benefit and help some users.
Though, there are some cases where the focus ring might not be great in your UI, the ones I can think of would be clickable icons, e.g. arrows ← → for pagination, hamburger icon to open a menu.
Also, in the case of a custom style <button>
having a high border-radius
, the outline
won't follow the rounded corners, and will result in this:
When clicking with a mouse or tap with your finger the added value of this focus ring is low (:hover
and :active
are probably better candidates), and it even adds useless noise to the UI. On the other hand, when tabbing through a website, users need to know that the focus is on the hamburger icon so that they can open the menu.
:focus-visible To The Rescue
The main difference between the two :focus
and :focus-visible
, is that you can use
:focus-visible
for people not navigating with a pointing device (mouse, touch, etc...).
That means that we can target people relying on keyboard navigation.
As of April 2019, it's implemented in Chrome only and behind a flag. However the good news is that if we still want to use this, we still can by using a polyfill github.com/WICG/focus-visible.
If in your codebase, you can remove the outline : none
that you had, install this polyfill, and update your CSS with this (as a first step)
/*
This will hide the focus indicator if the element receives focus via the mouse,
but it will still show up on keyboard focus.
*/
.js-focus-visible :focus:not(.focus-visible) {
outline: none;
}
This selector will filter out all the elements focused by a keyboard event, and won't apply in that case, so you can keep the default outline
by default.
A little detail that I really like in this spec is that :focus-visible
also applies in case the user focuses an <input>
field either with a mouse or a keyboard. Why? The rule is simple, if an interactive element opens the keyboard (on a mobile) it should keep the focus ring. I completely agree with this, even on desktop having an indication on where your caret is, can only be a good thing.
A workmate showed me this great example on how to get crazy with focus for keyboard navigation, there even are animations based on the direction when you navigate: sbb.ch/en/home.html
So let's end this era of :focus { outline: none; }
now that we have a reliable solution that works for everyone and can benefit to lots of people.
Ressources
A good read on the intent behind focus-visible
:
github.com/WICG/focus-visible/issues/128
Specifications:
drafts.csswg.org/selectors-4/#the-focus-visible-pseudo
Posted on April 25, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.