VGTech is a blog where the developers and devops of Norways most visited website share code and tricks of the trade… Read more



Are you brilliant? We're hiring. Read more

Hover state on touch devices

Frontend

With an increasing number of users on tablets and smartphones, the need to take touch friendliness into consideration is greater than ever. Even though both the browsers and hardware are approaching desktop speed, there are still some issues with implementing web sites and web apps for these devices.

The issue at hand
There is no hover state on touch devices, but the browsers usually render the hover state on the element the user has the finger on when the drag starts. The browsers, even though helpful with rendering the hover state, sometimes “forgets” removing the hover state. This leaves the page looking weird, and it’s impossible to fix with CSS hacks.

Shaun Inmans solution
The solution that that stood out as closest to “bullet proof” was the one proposed by Shaun Inman. It boils down to checking all css styling rules applied to the document and removing the ones containing the string ‘:hover’.

This works as long as you don’t target :hover and something else in the same rule. In that case the entire rule will be removed and the CSS quickly starts disintegrating..

Our minor tweak
To bypass this problem we tweaked Shauns solution so that the part of a selector that isn’t targeting the hover state is left intact. There doesn’t seem to be a way to alter the selector, so instead we remove the full selector and rule, and insert the new rule (without the hover stuff) in the same place in the style sheet object.

Show code
// disable :hover on touch devices
// based on http://retrogamecrunch.com/tmp/hover-fix
// via https://gist.github.com/4404503
// + https://twitter.com/javan/status/284873379062890496
// + https://twitter.com/pennig/status/285790598642946048
// re http://retrogamecrunch.com/tmp/hover
if ('createTouch' in document) {
    try {
        var pattern = /:hover\b/,
        sheet, rule, selectors, newSelector,
        selectorAdded, newRule, i, j, k;

        for (i=0; i<document.styleSheets.length; i++) {
            sheet = document.styleSheets[i];

            for (j=sheet.cssRules.length-1; j>=0; j--) {
                rule = sheet.cssRules[j];

                if (rule.type !== CSSRule.STYLE_RULE || !pattern.test(rule.selectorText)) {
                    continue;
                }

                selectors = rule.selectorText.split(',');
                newSelector = '';
                selectorAdded = false;

                // Iterate over the selectors and test them against the pattern
                for (k=0; k<selectors.length; k++) {
                    // Add string to the new selector if it didn't match
                    if (pattern.test(selectors[k])) {
                        continue;
                    }

                    if (!selectorAdded) {
                        newSelector += selectors[k];
                        selectorAdded = true;
                    } else {
                        newSelector += ", " + selectors[k];
                    }
                }

                // Remove the rule, and add the new one if we've got something
                // added to the new selector
                if (selectorAdded) {
                    newRule = rule.cssText.replace(/([^{]*)?/, newSelector + ' ');

                    sheet.deleteRule(j);
                    sheet.insertRule(newRule, j);
                } else {
                    sheet.deleteRule(j);
                }
            }
        }
    } catch(e){}
}

Pros and cons
+ No need to rewrite the style sheet.
+ No black magic with javascript events.
+ As a result of removing the hover selectors, there are no styles that could kick in when dragging etc.

– Depending on the number of style rules, the iteration over and testing the rules against the regex may be costly (timewise)..
– Truth be told it’s not sexy but it’s a solution

PHP. Javascript. Squash. @kbrabrand


1 comments

  • satoshi

    Great, thanks to this solution, I can sleep tonight.


Leave your comment