Last Updated: February 25, 2016
·
4.119K
· artinruins

Hover and Focus for no-touch, Active for Touch

iOS and Android are smart enough to use :hover and :focus styles on buttons, but in their own unique way. Long have my projects been plagued by hover states on buttons and links that persist after the users taps them. You might have encountered this as well…

What I came up with was a chain of Modernizr-added classes that limit accessible :hover and :focus classes to .no-touch browsers, while adding the same styles to an :active state when .touch is present, as well as a .no-js fallback.

Since the chain of classes is cumbersome, I made it all into a neat SASS mixin. Here is the mixin:

/*
 * Provide a hover effect for non-touch devices, turn it into an Active state for mobile, and maintain a fallback. 
 * @requires Modernizr as a JS dependency to get .no-touch classes
 * Adds styles via @content
 */
@mixin touch-hover() {
    .no-js &:hover, // the fallback
    .no-js &:focus, 
    .js.no-touch &:hover, // enhanced for no-touch
    .js.no-touch &:focus,
    .js.touch &:active { // relay same styles to active for touch devices
        @content; 
    }
}

To use, it can be placed inside an a declaration, like so:

a {
    color: blue; 

    @include touch-hover() {
        color: purple; 
    }
}

To apply it to a specific class, the mixin must be applied inside that class, like so (since it relies on the & operator):

.anchor {

    @include touch-hover() {
        color: purple; 
    }
}

The result is as expected on desktop/mouse-pointer devices. For touch screens, though, the hover styles are applied only when the button is tapped. They go away after the tap is complete.

This has been tested, but not extensively. I'd like to hear any comments about which browsers ignore these rules, and what happens when you have a device that supports both touch and pointer events at the same time.