Like Eric Bailey says, if it’s interactive, it needs a focus style. Perhaps your best bet? Don’t remove the dang outlines that focusable elements have by default. If you’re going to rock a button { outline: 0; }
, for example, then you’d better do a button:focus { /* something else very obvious visually */ }
. I handled a ticket just today where a missing focus style was harming a user who relies on visual focus styles to navigate the web.
But those focus styles are most useful when tabbing or otherwise navigating with a keyboard, and less so when they are triggered by a mouse click. Now we’ve got :focus-visible
! Nelo writes:
TLDR;
:focus-visible
is the keyboard-only version of:focus
.Also, the W3C proposal mentions that
:focus-visible
should be preferred over:focus
except on elements that expect a keyboard input (e.g. text field,contenteditable
).
(Also see his article for a good demo on why mouse clicking and focus styles can be at odds, beyond a general dislike of fuzzy blue outlines.)
Browser support for :focus-visible
is pretty rough:
This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.
Desktop
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
86 | 4* | No | 86 | 15.4 |
Mobile / Tablet
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
123 | 124 | 123 | 15.4 |
But it does have Firefox support, and as Lea Verou says:
… once Chrome ships its implementation it will explode in a matter of 1-2 months.
That’s generally how things go these days. Once two major browsers have support — and one of them is Chrome — that’s a huge enough slice of the web that can start using it. Especially when it can be done as safely as this property.
Safely, as in, there is an official polyfill, meaning you can nuke default focus styles and just use :focus-visible
styles:
/* Remove outline for non-keyboard :focus */
*:focus:not(.focus-visible) {
outline: none;
}
/* Optional: Customize .focus-visible */
.focus-visible {
outline: lightgreen solid 2px;
}
But, as Patrick H. Lauke documented, you can do it even without the polyfill, using careful selector usage and un-doing styles as needed:
button:focus { /* Some exciting button focus styles */ }
button:focus:not(:focus-visible) {
/* Undo all the above focused button styles
if the button has focus but the browser wouldn't normally
show default focus styles */
}
button:focus-visible { /* Some even *more* exciting button focus styles */ }
Seems like a nice improvement for the web.
Glad to see some more coverage of focus states, and
:focus-visible
. Some thoughts:What is a keyboard-only user? Rapid input mode-switching is especially prevalent in this day in age, where mainstream devices can switch between touch, mouse, keyboard, and other input like voice on the fly. Think of the last time you tabbed through a form, but clicked on the submit button with a cursor. Starting to segregate users into those who use keyboard and those who don’t makes a lot of assumptions about their circumstances and methods of browsing, and that really doesn’t sit well with me.
Also consider things such the level of tech literacy of the end user. An inconsistent focus effect can be confusing to someone who isn’t familiar the nuances of navigating through a digital system, as the reason why a focus ring is or is not appearing is not directly communicated to them. This is compounded by if the user has low vision considerations, as the predictability of where it appears is altered.
Also, unlike CSS, JavaScript is not fault-tolerant. If the Polyfill portion of the script breaks, focus effects are lost, rendering the site inoperable to those who rely on focus indicators. This is to say nothing about support concerns for non-standard browsers.
I’m clearly skeptical of
:focus-visible
‘s actual utility, but I also think the stakes are really high.I completely agree here. After I found out the power of good accessibility controls on a website after working on a personal project, I’ve found myself more and more using both keyboard and mouse based navigation.
I’m all for new tools and syntaxes and I think this looks interesting, having said that though, the support for this is poor and whilst a Polyfill might get you on your way, I don’t think the power of
:focus
can be ignored. Whilst this appears as a fun new thing for some, it’s the difference between literally using the web and not being able to. Something people (myself included) take for granted.Good write-up though. I’ll look forward to seeing this being implemented in more browsers and seeing how we can leverage both options. Nothing says we can’t use them in tandem to create a great experience for abled users and less abled users.
This exchange gets a little heated, but seems related…
We use a different approach in our React apps.
i.e. “what-input” Node package, which adds following attributes to HTML element
<html data-whatinput="keyboard" data-whatintent="keyboard">
.We then leverage like this to supply :FOCUS styles for keyboard only:
And :HOVER styles for mouse:
I usually use an HTML version of this. The technique involves adding an element within the element you want to give styles to.
You then style the
:focus
for the main element.As the user clicks on it, the
<span>
element gains focus and the focus ring isn’t shown.I’m looking forward to
:focus-visible
– that’ll definitely save some markup!In the meantime – until
:focus-visible
gets browser support – there are other ways of achieving keyboard-only focus styles. Here is an article with a CSS solution: https://www.kizu.ru/keyboard-only-focus/#x – Codepen [Here] (https://codepen.io/danield770/details/RgzLrm/) It’s a bit messier than the pseudo element, but it does the job!