Links with mouseover (or hover) styles on touch devices are a bit of a dilemma. In short: they don’t really exist on these devices. Creating fancy :hover styles can really add to the browser experience and help simplify your layout, but they simply will not work on a touch device. When a tablet or smartphone user taps your hover-styled link elements, the hover style shortly appears, and immediately the underlying link is followed/activated.

So how do we handle this problem? Do we sniff out touch devices and disable hover classes? Not at all: it can be fixed using JavaScript (specifically jQuery in this case), and with some minimal adjustments you can keep using your hover styles across all browsing devices. Here’s how:

The goal

When a touch user taps link A, only the hover style for link A is activated but the link does not open. After this, there are two possible options:

  1. User taps link A again -> link A is opened.
  2. User taps link B -> mouseover for link B is activated and the hover style for link A is deactivated.

Another thing to keep in mind is that if a user taps link A, then taps link B and then taps link A again, it should not consider link A as being tapped for a second time (which would lead to the browser to open the link).

What we need to accomplish

To realize our goal, we need to accomplish the following using JavaScript (jQuery)

  1. User taps the ‘tappable hover’ link
  2. Does the link have a hover class?
  3. If it does, allow the click to proceed (return true)
  4. If it does not, add the hover class, remove it from all other tappable hover links, and prevent the click from continuing (preventDefault)

That’s it.

The (example) HTML

Specify a class for the link elements you want to enable hover for, as we will use this class in the jQuery selector (in this case taphover).

<a class="taphover" href="">Link 1</a>
<a class="taphover" href="">Link 2</a>
<a class="taphover" href="">Link 3</a>

The CSS

Make sure you specify both pseudo (:hover) and class (.hover) for the link, so that they appear the same on both a touch device and regular browser:

a.taphover:hover, a.taphover.hover {
    // css for hovering here
};

jQuery

To target just touch devices, I use the touchstart event on the links to bind to.*

$('a.taphover').on('touchstart', function (e) {
    'use strict'; //satisfy code inspectors
    var link = $(this); //preselect the link
    if (link.hasClass('hover')) {
        return true;
    } else {
        link.addClass('hover');
        $('a.taphover').not(this).removeClass('hover');
        e.preventDefault();
        return false; //extra, and to make sure the function has consistent return points
    }
});

View/fork on Github: https://gist.github.com/c-kick/31dfbfe7b948c16d17c8

That’s it, this should do he trick.

Demo

I’ve set up a working Fiddle here. Visit it using a touch device, or using debug tools like Chrome’s web inspector, which can simulate touch.

Note: the script will traverse the entire DOM, looking for .taphover links on which to remove the hover class. This is potentially inefficient, so adjust it as you seem fit. I suggest using a selector context for optimizing performance if needed.

* Note that binding to the touchstart event, and setting preventDefault() in the process will cause any other touches on the element(s) to fail. This means that if a user starts swiping/scrolling, starting on one of these links would disable the swipe. A work-around is to sniff out touch devices with something like Modernizr, and then binding to the regular click event.