Thomas Fuchs
Hi, I'm Thomas Fuchs. I'm the author of Zepto.js, of script.aculo.us, and I'm a Ruby on Rails core alumnus. With Amy Hoy I'm building cheerful software, like Freckle Time Tracking and Every Time Zone and write books like Retinafy.me.
   Want me to speak at your conference? Contact me!

Why and how to not use hover styles on touch devices

January 26th, 2013

ipadButtons that show only on hovering over an area with the mouse are a great (if controversial) way to declutter user interfaces on traditional desktops where users have a mouse or trackpad. On mobile devices (phones and tablets), users use their finger instead, and there’s no more way to just hover over an element on a webpage—hovering and “clicking” are invoked by the same action: tapping.

Mobile browsers solve this issue by having the first tap invoking the hover style of an element and, if applicable, the second tap invoking any “click” events. Because of the need to discern swipes and taps, there’s a noticeable delay in browser response time. What this adds up to is that when you have both a :hover style and a onclick event on, say, a contained button in the :hover area, users end up spending the better part of a second trying to invoke the “click” on the button (300ms for the hover tap, 300ms for the click tap, and extra time for lifting the finger in-between).

The easiest way to deal with this is simple: don’t use :hover on touch-enabled devices.

Here’s one way I solved this in Freckle Time Tracking:

  1. I use Zepto’s detect module to see if I’m on a tablet or phone (you can use this module independently of Zepto, it doesn’t have dependencies on it).
  2. If it’s a tablet or phone, I add a “no-hover” CSS class to the BODY element
  3. I disable any :hover styles with selectors that use body.no-hover .... You actually don’t have to redefine the :hover rule, just make sure the normal rule and the :hover rule contain the same CSS property settings (like visibility:visible)

Now, my reason for not feature-testing (sue me!) for support of touch events and instead using browser sniffing is that 1) historically detection of touch events has been unreliable, 2) there are hybrid browsers and devices that support both touch and normal mouse events, and 3) it’s faster.

Update Jan 26, 7:50pm ET: Here are two more variants on this, the first one is from Thijs van der Vossen, and is a short JavaScript snippet that you can inline in your HEAD element. It adds multiple classes to HTML, depending on the environment it’s run in. The second variation is a CoffeeScript function to automatically remove :hover rules from Mislav Marohnić (assumes a modern, properly DOM-compatible browser).