Accessible :hover styles
March 06, 2022Long ago, I wrote that since you couldn't touch :hover
effects, it was best to focus on other ways to let users know something was interactive. In short, hover effects are mostly limited to desktop browsers, which means many users will be left with fewer clues about what is interactive.
While the point still stands, there are some new options available that weren't when I first wrote about the topic.
To recap the problem: there are plenty of reasons to add hover effects to elements by making use of the :hover
pseudo-selector. As an example, if you don’t want links to have an underline by default, but you want an underline to show when the user hovers…
a { text-decoration: none; }
a:hover { text-decoration: underline; }
That works... but you’ve got a problem. For all practical purposes, mobile users won’t see the underline and that has a negative effect on usability.
Instead, let’s make it so links will have an underline by default, then add a media query to check if the browser supports :hover
, and if it does, we can progressively enhance from there.
a { text-decoration: underline; }
@media (hover: hover) {
a { text-decoration: none; }
a:hover { text-decoration: underline; }
}
This gets us 80% of the way there, but there’s one more gotcha if you want to finish it properly: some Android devices mimic a hover input by way of a long-tap so Android will lie to itself and claim to support :hover
when it really doesn't. To address this you need one additional query: (pointer: fine)
.
a { text-decoration: underline; }
@media (hover: hover) and (pointer: fine) {
a { text-decoration: none; }
a:hover { text-decoration: underline; }
}
(pointer: fine)
checks whether the the primary input method is fine like a mouse, or coarse as in touch input.
By combining hover: hover
and pointer: fine
queries, you can properly enhance your pages with hover effects where appropriate without completely chucking usability in the bin for the rest of your users.