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
Top comments (2)
I agree that
:focus-visible
is cool and all, but if an element is clicked and takes focus because of that, the UI should explain that to the user. Otherwise, how does low visibility but high dexterity user know what will happen when then subsequently use theenter
orspace
keys to interact with the page?They need to know what will happen visually. I can get the "let's not make it ugly" approach, but we could do that even without
:focus-visible
, we just need to put some common sense after outoutline: none;
declarations...Even if there is long term benefit in distinguishing between focus applied by the keyboard and focus applied by the mouse, we can't simply stop showing the focus that comes with the mouse, it's still happening and cause side effects. In cases where
:focus-visible
is used, we should be backing it up with a:focus
state that is acceptable in these contexts. Then we can both appease picky designers and support users who deserve high-quality experiences when using our applications.I have been looking into this. Unfortunately the flag issue is a major barrier. The fact that extra JS is needed to make it work feels dirty. A solution that works quite well is a slight change of how the HTML and CSS is structured. This article should help anyone who needs it: thoughtsandstuff.com/focus-style-c...