Focus Style for Keyboard Navigation Only

jeromesm

Jerome Smadja

Posted on April 25, 2019

Focus Style for Keyboard Navigation Only

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.

Example of a click on a hamburger icon to open a menu which also shows the native outline focus ring

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:

button with native outline when focused

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;
}
Enter fullscreen mode Exit fullscreen mode

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

💖 💪 🙅 🚩
jeromesm
Jerome Smadja

Posted on April 25, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related