I want to ignore all :hover
CSS declarations if a user visits our website via touch device. Because the :hover
CSS does not make sense, and it can even be disturbing if a tablet triggers it on click/tap because then it might stick until the element loses focus. To be honest, I don't know why touch devices feel the need to trigger :hover
in first place - but this is reality, so this problem is reality as well.
a:hover {
color:blue;
border-color:green;
// etc. > ignore all at once for touch devices
}
So, (how) can I remove/ignore all CSS :hover
declarations at once (without having to know each one) for touch devices after having them declared?
tl;dr use this: https://jsfiddle.net/57tmy8j3/
If you're interested why or what other options there are, read on.
You can remove all the CSS rules containing :hover
using Javascript. This has the advantage of not having to touch CSS and being compatible even with older browsers.
function hasTouch() {
return 'ontouchstart' in document.documentElement
|| navigator.maxTouchPoints > 0
|| navigator.msMaxTouchPoints > 0;
}
if (hasTouch()) { // remove all the :hover stylesheets
try { // prevent exception on browsers not supporting DOM styleSheets properly
for (var si in document.styleSheets) {
var styleSheet = document.styleSheets[si];
if (!styleSheet.rules) continue;
for (var ri = styleSheet.rules.length - 1; ri >= 0; ri--) {
if (!styleSheet.rules[ri].selectorText) continue;
if (styleSheet.rules[ri].selectorText.match(':hover')) {
styleSheet.deleteRule(ri);
}
}
}
} catch (ex) {}
}
Limitations: stylesheets must be hosted on the same domain (that means no CDNs). Disables hovers on mixed mouse & touch devices like Surface or iPad Pro, which hurts the UX.
Place all your :hover rules in a @media
block:
@media (hover: hover) {
a:hover { color: blue; }
}
or alternatively, override all your hover rules (compatible with older browsers):
a:hover { color: blue; }
@media (hover: none) {
a:hover { color: inherit; }
}
Limitations: works only on iOS 9.0+, Chrome for Android or Android 5.0+ when using WebView. hover: hover
breaks hover effects on older browsers, hover: none
needs overriding all the previously defined CSS rules. Both are incompatible with mixed mouse & touch devices.
This method needs prepending all the hover rules with body.hasHover
. (or a class name of your choice)
body.hasHover a:hover { color: blue; }
The hasHover
class may be added using hasTouch()
from the first example:
if (!hasTouch()) document.body.className += ' hasHover'
However, this whould have the same drawbacks with mixed touch devices as previous examples, which brings us to the ultimate solution. Enable hover effects whenever a mouse cursor is moved, disable hover effects whenever a touch is detected.
function watchForHover() {
// lastTouchTime is used for ignoring emulated mousemove events
let lastTouchTime = 0
function enableHover() {
if (new Date() - lastTouchTime < 500) return
document.body.classList.add('hasHover')
}
function disableHover() {
document.body.classList.remove('hasHover')
}
function updateLastTouchTime() {
lastTouchTime = new Date()
}
document.addEventListener('touchstart', updateLastTouchTime, true)
document.addEventListener('touchstart', disableHover, true)
document.addEventListener('mousemove', enableHover, true)
enableHover()
}
watchForHover()
This should work basically in any browser and enables/disables hover styles as needed.
Here's the full example - modern: https://jsfiddle.net/57tmy8j3/
Legacy (for use with old browsers): https://jsfiddle.net/dkz17jc5/19/