Media query for devices supporting hover

not should prefix media type (screen, print, all, etc) and not media feature (hover, point, etc).

Wrong:

@media not (hover: none)

Correct:

@media not all and (hover: none)

Yes, its unintuitive and weird. Source (see comments).

So you do not need javascript to alternate result of media query.


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.


From the specs:

none

Indicates that the primary pointing system can’t hover, or there is no pointing system. Examples include touchscreens and screens that use a drawing stylus.
Pointing systems that can hover, but for which doing so is inconvenient and not part of the normal way they are used, also match this value.

For example, a touchscreen where a long press is treated as hovering would match hover: none.

If your browser (mobile/touch) support long-press to simulate hover, the usage of hover: none will not work. What you can do is just use a default value and override it (with default css precedence):

body {
    background: red;
}

@media (hover: hover) {
  body {
    background: blue;
  }
}

Desktop will have blue background and mobile/touch will have red background

Check the following example:
https://jsfiddle.net/mcy60pvt/1/

To check the long-press option of the mobile you can use this example:
https://jsfiddle.net/mcy60pvt/3/

In the above example the green block has :hover definition for both desktop and mobile, however for desktop the background will change to yellow and for mobile (with long-press) it will change to white.

Here is the css for the last example:

body {
    background: red;
}
div.do-hover {
  border: 1px solid black;
  width: 250px;
  height: 250px;
  background: green;
}
div.do-hover:hover {
  background: white;
}

@media (hover: hover) {
  body {
    background: blue;
  }
  div.do-hover:hover {
    background: yellow;
  }
}

In this example - browsers that don't support :hover will view the hover me box with green background, and while "hover" (touch/long-press) - the background will change to white.

update

As for the added pseudo code:

.myelement {
    /* some styling #1 */
    /* note: no hover state here */
}
@media(hover: hover) {
    .myelement {
        /* some styling that override #1 styling in case this browser suppot the hover*/
    }
    .myelement:hover {
        /* what to do when hover */
    }
}