You find a lot of edge cases building UI's. Accessibly opening a modal, scroll-lock, strange focus states, etc..., and the solution to those edge cases aren't always apparent.
Well, I just found one that I already knew the answer too but forgot- so I'm writing this article to cement in my head and share the knowledge with all of you!
What is :focus-visible?
According the MDN, :focus-visible
is a pseudo-class that applies while an element matches the :focus
pseudo-class and determines vie heuristics that the focus should be made evident on the element.
In human speak? The browser determines if the :focus
came from a click event or keyboard event and applies the styles accordingly. In most cases, that means that it won't apply the :focus
styles from a click event.
That means that you give your keyboard users the focus styles they may want/need/desire without having a potentially jarring user experience for your mouse users.
What was the problem?
The issue I ran into was that I needed an element to have focus styles for accessibility's sake- but I didn't need some of those focus styles to apply when it was clicked.
To be even more clear, the hover and focus styles are the same. I wanted the hover styles to apply on hover but I didn't need the focus styles to linger after the element was clicked.
.logo-link:hover,
.logo-link:focus,
.initial-display {
.logo-text {
@apply translate-y-0;
}
.logo-type {
@apply opacity-100;
}
.logo-tagline {
@apply opacity-80;
}
}
You can see there wasn't much to the styles, but the client was adamant about this user experience.
The Solution
The answer to this problem was only 8 characters long!
Adding -visible
to the end of the :focus
pseudo-class was all it took.
.logo-link:hover,
.logo-link:focus-visible,
.initial-display {
.logo-text {
@apply translate-y-0;
}
.logo-type {
@apply opacity-100;
}
.logo-tagline {
@apply opacity-80;
}
}
Now I can see clearly
I was absolutely ready to go town with javascript by using a click event to force .blur()
and be as strong-handed as I needed to be to make it work.
I mentioned earlier that I knew this answer, but that I didn't come to this solution on my own. A co-worker suggested :focus-visible
and it immediately came rushing back.
I ran into this exact problem a couple of months and the fix was the exact same thing!
Can I Use
There is one caveat to :focus-visible
, and that is that it doesn't have full browser support yet.
You can see in the image below that it has decent coverage of around 70%, but it has 0 support in Safari, so you'll have to be sure to cover all of your bases and add in some polyfills.
Top comments (2)
A pattern I've been using a lot recently is use a couple of @supports to use the default focus in IE and fallback to
:focus
in browsers where:focus-visible
is not supported.I love this. Adding it to the toolbelt!