Media Query for Devices Supporting Hover

Media query for devices supporting hover

Thanks to Dekel's comments I solved this by running the logic in JS and applying a class instead:

e.g.

const canHover = !(matchMedia('(hover: none)').matches);
if(canHover) {
document.body.classList.add('can-hover');
}

Then in the stylesheet:

.myElement {
background: blue;
}
.can-hover .myElement:hover {
background: red;
}

I've tested this on desktop Chrome, Safari and Firefox, and iOS Safari and it works as expected.

CSS: How to allow the hover state only on devices which support hover?

I achieved to only hover on devices which have a real hover state with two media queries.

  • The first media query makes sure that the CSS is only executed when the current device has a real hover state. This works in nearly every browser: https://caniuse.com/#feat=css-media-interaction
  • The second media query is to support IE11 because the first one isn't supported by IE11 https://developer.mozilla.org/en-US/docs/Web/CSS/@media/-ms-high-contrast

@media (hover: hover), (-ms-high-contrast:none) {  div:hover {    background: red;  }}
<div>Hover me!</div>

Does the media query operator not actually work?

According to MDN

if you use the not or only operators, you must explicitly specify a media type.

This snippet adds screen to the media query in your question.

On a laptop without touch screen it appears to work, that is hovering over the div does change it to cyan. If you change the 'coarse' to 'fine' then the hover does not work because the laptop's mouse is considered a fine pointer.

div {
width: 20vmin;
height: 20vmin;
background: pink;
}

@media not screen and (any-pointer: coarse) {
div:hover {
background: cyan;
}
}
<div></div>

Detect if a client device supports :hover and :focus states

The W3C seems to have recognized this problem and has introduced the hover feature:

The hover media feature is used to query the user’s ability to hover
over elements on the page with the primary pointing device. If a
device has multiple pointing devices, the hover media feature must
reflect the characteristics of the “primary” pointing device, as
determined by the user agent. (To query the capabilities of any
available pointing devices, see the any-hover media feature.)

There is even a media query to check if there is any possibility to hover:

The any-pointer and any-hover media features are identical to the
pointer and hover media features, but they correspond to the union of
capabilities of all the pointing devices available to the user. In the
case of any-pointer, more than one of the values can match, if
different pointing devices have different characteristics.

Code samples:

/* Primary input mechanism system can 
hover over elements with ease */
@media (hover: hover) { ... }

/* Primary input mechanism cannot hover
at all or cannot conveniently hover
(e.g., many mobile devices emulate hovering
when the user performs an inconvenient long tap),
or there is no primary pointing input mechanism */
@media (hover: none) { ... }

/* One or more available input mechanism(s)
can hover over elements with ease */
@media (any-hover: hover) { ... }


/* One or more available input mechanism(s) cannot
hover (or there are no pointing input mechanisms) */
@media (any-hover: none) { ... }

Official draft: https://drafts.csswg.org/mediaqueries/#hover

This feature is still at risk, but I really hope it will be fully supported soon as it is already widely supported: https://caniuse.com/#feat=css-media-interaction

Further read: https://css-tricks.com/touch-devices-not-judged-size/

For Chrome test your device here: https://googlechrome.github.io/samples/media-hover-pointer/

Test with JavaScript: https://jsfiddle.net/Blackbam/zkd2cs0t/16/

The best solution for now is most probably to use those media queries with a fallback solution using touch detection via document.createEvent("TouchEvent"); and mouse detection via mousemove.hasMouse.

How to remove/ignore :hover css style on touch devices

2020 Solution - CSS only - No Javascript

Use media hover with media pointer will help you resolve this issue. Tested on chrome Web and android mobile. I known this old question but I didn't find any solution like this.

@media (hover: hover) and (pointer: fine) {
a:hover { color: red; }
}
<a href="#" >Some Link</a>

How to handle CSS media query negation including browsers which do not support it?

This is a little tricky; since the only way to apply styles for when a browser doesn't support a particular media feature is by taking advantage of the cascade, you'll need to apply the fallback style outside a @media rule altogether. This does come at a slight cost of duplicating some styles, unfortunately: