As most mobile web application developers already will know there is a very disturbing issue known as the onClick delay.
The problem in brief
Skip this section if you’re familiar with the problem.
You can eliminate this delay by using touch events and adding touchstart listeners instead of click listeners but they have a nasty side-effect: After the touchstart / (touchmove) / touchend cycle a click event will still be triggered, completely isolated from the touch events.
This means that when your touchstart (or tap) listeren has done it’s magic, like changing the HTML or initiating some server interaction a click event will follow on (pretty much) the same coordinates that the touch event took place. But since your HTML already got updated this might very well be a click on some other element causing undesired “ghost” interaction with your website / web-app.
Solution 1 – clickbusters
There have been several attempts to solve this issue that are all very similar, apparently called “clickbusters”.
What clickbusters essentially do is that replace click events by touch events. When you tap somewhere they will try to determine if it’s a ghost click and prevent the handler from being executed.
- jQuery Mobile’s vmouse events – part of jQueryMobile - tested, not foolproof.
jQuery Mobile offers a vmouse event binding that replaces click handlers for touch handlers if the browser supports them. When a touch event is received it records the coordinates of that events so that when a click event shows up, somewhere in it’s event handler structure, it will try to figure out if this click happened at roughly the same coords and thus is a ghost click or not.
Liberally quoting jQueryMobile contributor Todd Parker: “jQuery has the vclick plugin but that still doesn’t solve the problems mainly because Android’s event system is a mess ()”
- Touch to Click – jQuery plugin – tested, not foolproof.
You simply include this plugin into your jQuery / jQueryMobile powered project and voilá, click events have been replace by touch events.
It is different from jQueryMobile’s vmouse in the sense that it doesn’t care about coordinates. It basically tries to capture any click that is triggered within a configurable amount of time after the touch event.
Initially this solution seemed to be better than the vmouse approach but I realized that there were a lot of devices (both Android and iOS) that didn’t take this thing very well either.
- A script by Google that does the same as jQueryMobile’s vmouse - not tested.
A blog entry called “Creating Fast Buttons for Mobile Web Applications” on the Google Developer blog describes some code that is very similar to the before mentioned “vmouse” but does not use jQuery or jQueryMobile.
Solution 2 – disable zooming
In the Google Developer Blog article mentioned above the author makes an interesting statement:
Although disabling zooming might not be an option for everyone, it sounds like another solution for the native Android browser on Android 2.3 and higher is to add the following viewport meta tag:
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
I have tried this and tested it on Google Nexus One (Android 2.3) and Google Nexus S (4.1.2) and Google Galaxy Nexus (4.1.1) but I can’t say I’ve noticed any significant difference.
Solution 3 – Be content concious
The lamest but possibly the most effective solution is to make sure that when your content changes after a tap event, that there is no clickable content in it’s place in the subsequent page.
Or you could add a semi transparent div on top of everything (completely or semi-transparent) which avoids click event to reach the underlying content.
There is a lot of tricks you can apply but there’s no one solution to rule them all yet.
I am very confident this issue will be solved by the browser manufacturers in the future for there is no doubt in my mind that web applications have a great future before them.