FastClick: native-like tapping for touch apps
This post was originally made on the Assanka blog. Assanka was acquired by the Financial Times in January 2012, and became what is now FT Labs. Learn more.
Treating a ‘tap’ as a ‘click’ is the practical approach. On iOS at least, there’s no onTap event –
onClick has been repurposed for that role. But in order to properly handle multiple-touch gestures like pinching or even double-taps, some compromises have to be made. One of these is the roughly 300ms delay between a tap and the firing of a click event, which can make your apps feel laggy and unresponsive even when it’s not technically so.
The technique we use to get around this problem is to track all
TouchStart events in our app and fire a click event as soon as we receive a
TouchEnd event (unless some application-specific exception is satisfied).
As we refined our fast-clicking code, we turned it into a small and efficient library, which we call FastClick. This code has been tried and tested by hundreds of thousands of users, and so far has proved to be very robust. We’d love to know what others are doing to address this challenge and find ways of improving our own approach, and to help kick off that process, we’re open-sourcing FastClick today. We’d encourage you to try it out, and let us know what you think.
To use FastClick, instantiate it on the layer you’d like to be fast-clickable – we use
document.body because we want all our buttons and links to receive fast clicks. In your event listeners, ‘click’ events synthesised by FastClick will have the
forwardedTouchEvent property set to true.
If you use buttons and iOS-style menus in your app then there’s a good chance your interface feels unresponsive on touchscreen devices. Here’s a simple example of how we solve that problem for a single button by instantiating FastClick on it:
In the example, the button with a
fastclick class will have its click handler called as soon as your finger is lifted off the screen, while tapping on any other buttons on the page will trigger the same handler after a noticeable delay. Try the live demo.
select element doesn’t behave normally when receiving (synthesised) programmatic clicks, so if you apply FastClick to an element that contains selects, FastClick will ignore clicks on the select and allow the normal click event to fire.
If you want any other elements (besides selects) in your FastClick layer to receive non-programmatic clicks, you’ll need to use one of two classes:
touchandclickevent. For any clickable element in a FastClick layer, tapping the element will cause different effects depending on how you use these classes:
- No class: The element will receive only a programmatic click from FastClick. The default click event triggered by the user will be suppressed.
clickevent: The element will receive only the default click event, and will be ignored by FastClick
touchandclickevent: The element will receive both the default click event AND a programmatic click from FastClick (the FastClick one will be triggered first). This is only safe if your handler’s action is idempotent.
Here’s an example of all three:
When is this useful? Try the other live demo we’ve built using a click event handler that attempts to trigger focus on an
input element. iOS will only allow focus to be triggered on other elements within a handler function if the event that triggered it was non-programmatic.
We’ll be posting updates and answering questions on this blog. If the interest reaches a stage where FastClick could benefit from the developer community, we’ll move to a public repository host. But for now, concentrate on giving your users the best response time they can get – download FastClick (or minified) and give it a go. Its free to use in all your apps, and licensed under the MIT license.