I'm not touching you:Handling Hover States on Touch Screens

TL;DR: Use the hover and/or pointer media queries. Or read these awesome articles over at CSS Tricks.

Here's a seemingly simple challenge: how do you design an interaction tailored for both touch-enabled devices and traditional user inputs?

Say we're building a horizontal collection of items. On mobile, we're aiming for that familiar edge-to-edge experience, where items peek out from one side and users simply swipe through to see them; on desktop, we want to add some clean-cut arrows and butter-smooth scrolling to let users paginate through. Scripting details aside, how do we make sure those aforementioned arrows only show up for users who can't swipe left?

If you're like me, you might be tempted to naïvely slap a :hover selector together and call it a day—sprinkle in a few display: nones and you're set, right? Simulation looks good in the dev tools. After all, you can't exactly hover without a mouse, can you?

Well, turns out it's complicated.

In reality, what happens on most modern touch devices is this: when a user first taps on the element, the hover state becomes active; in fact, until the user taps elsewhere, that style ends up "sticking" even as the user may drag their finger to scroll. You can see it in action in this codepen here (try it out on a mobile device).

Not the effect we were going for at all. In some instances, this behavior yields an unpolished user experience; in others, it can be downright disruptive.

So, what can we do? Sure, we could write some JavaScript to do some roundabout touch detection, but having that logic live in both our stylesheets and our scripts is messy and can be difficult to de-tangle later. Thankfully, there is a better way: enter Level 4 media queries.

Instead of assuming which devices support an interaction like hover, now we can simply ask:

/**
 * The following styles are applied only when the
 * device's primary input mechanism is able to hover:
 */
@media (hover: hover) {
  button:hover {
    /* ... */
  }
}

/**
 * Likewise, these styles will only be applied when
 * the primary input mechanism does NOT support hovering:
 */
@media (hover: none) {
  button:hover {
    /* ... */
  }
}

Take another look at our Codepen example, this time with these media queries added.

Notice that this only detects the user's primary input mechanism—if you need to assert whether any input mechanism supports it (e.g. devices sporting both a mouse and a touch screen), you would replace the query with any-hover:

@media (any-hover: hover) {
  a:hover {
    /* ... */
  }
}

So that's it?

Yes, but with caveats. While hover strictly tests whether a user can hover over an element, you might want more information about that user's device in order to determine whether they should. As the W3C spec illustrates:

A number of smart TVs come with a way to control an on-screen cursor, but it is often fairly basic controller [sic] which is difficult to operate accurately.

In situations like this, a design decision must be made: do you want to show interactive elements on devices like this? If so, great! If not, hover has a counterpart that may come in handy here: pointer. Like hover, pointer evaluates the primary pointing device (if one exists) and tests the accuracy of that device; likewise, its complement any-pointer evaluates the accuracy of any pointing devices that exist.

These can even be used in combination to further refine the parameters of your styles:

/**
 * You'll really only see me with a mouse or touch pad
 * @see https://www.w3.org/TR/mediaqueries-4/#mf-interaction
 */
@media (hover: hover) and (pointer: fine) {
  .my-class:hover {
    /* ... */
  }
}

But can I use it, though?

Depending on your support requirements, this approach may be a non-starter; however as of this writing, browser support for these queries is fairly broad: by early 2019, all major browsers (save for IE) had full support. For our particular use-case, this approach worked great. If you can, I highly encourage you to give it a try.

In the end though, who knows? Perhaps one day our beloved touch screens will detect when our fingers hover over that "Place Order" button. As engineers, I'm sure we'll look forward to that, Greg.

David Can't Wait

Sources