29

I'm using the below code to bind "click" or "touchstart" events (using jQuery's on(eventType, function() { ... })).

var what = (navigator.userAgent.match(/iPad/i)) ? 'touchstart' : 'click';

Later on:

$foo.on(what, function() { ... });

... which works great for iPad and "everything else", but I'm concerned that the above code has "iPad tunnel vision"...

My question(s):

Do all other devices (for example, Android tablets) have similarly named "touchstart" events? If so, how can I improve the above code so that I can account for those event types?

In other words, how can I account for a wider range of touch devices in above code (not just iPad)?


EDIT #1

What do you folks think about this:

var foo = ('ontouchstart' in window) ? 'touchstart' : ((window.DocumentTouch && document instanceof DocumentTouch) ? 'tap' : 'click');

Note: Most of the above logic is from Modernizr here.

The above appears to work for Firefox/iPad... I don't have much else to test on at this time.

What I like about the above is that I'm not UA sniffing. :)

Is tap a good default for all other touch devices?


EDIT #2

Some interesting information here, which links to this:

Creating Fast Buttons for Mobile Web Applications

Not a direct answer really, but gives a lot of details of the situation devs face when facing click-related events for multiple platforms and devices.


EDIT #3

Some good info here too:

Android and iPhone touch events

Android and iPhone versions of WebKit have some touch events in common:

touchstart - triggered when a touch is initiated. Mouse equivalent - mouseDown
touchmove - triggered when a touch moves. Mouse equivalent - mouseMove
touchend - triggered when a touch ends. Mouse equivalent - mouseUp. This one is a bit special on the iPhone - see below
touchcancel - bit of a mystery

After reading that, I think I'll change the code above to this:

var foo = (('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)) ? 'touchstart' : 'click';

When I first asked my question - not having access to anything other than an iPad/iPhone - I assumed touchstart was an iOS-specific event; it now looks like touchstart and click will cover most, if not all, of the bases for touch devices.


August 2014 update:

If it's of any help, I've posted some utility classes here:

  • mhulse / no-x.js:

    [no-js] [no-touch] JavaScript utilities to put in of HTML templates that will add js or touch classes for use in CSS and/or JS.

Community
  • 1
  • 1
mhulse
  • 4,062
  • 6
  • 28
  • 35
  • 1
    What happens when you bind multiple events? `$foo.on('touchstart click tap etc', function() { ... });` – Adam Merrifield Jul 10 '12 at 04:00
  • Based on this question, it looks like `var what = (/(iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent)) ? 'touchstart' : 'click';` might cover more bases. – mhulse Jul 10 '12 at 04:07
  • @AdamMerrifield Thanks for the reply! That's a great question... Is `tap` what other devices use? Would there be any drawbacks to binding multiple events at once (perhaps, checking `e.type` could get a little squirrely... and what about performance issues?) Still though, it's a good idea/question... **I wouldn't mind getting away from UA sniffing.** Hmmm, I need to test some; I'll be back with my findings. Thanks!!! – mhulse Jul 10 '12 at 04:11
  • Above, when I say "based on this question", I meant to link that text to [this question here](http://stackoverflow.com/questions/4460205/detect-ipad-iphone-webview-via-javascript). – mhulse Jul 10 '12 at 04:31
  • For what it's worth, I found a list of events, and some interesting code, [here](https://github.com/jquery/jquery-mobile/blob/master/js/events/touch.js): `touchstart, touchmove, touchend, tap, taphold, swipe, swipeleft, swiperight, scrollstart, scrollstop`. – mhulse Jul 10 '12 at 05:19

3 Answers3

14

I would strongly suggest against using UA in order to determine whether you're under touch environment.

Use Modernizr instead: http://modernizr.com/ The below code would recognize anything but windows phone 7 because the windows phone 7 does not fire the regular browser touch events. However WP8 would most probably be recognized correctly.

if (Modernizr.touch){
   // bind to touchstart, touchmove, etc and watch `event.streamId`
} else {
   // bind to normal click, mousemove, etc
}
Konstantin Dinev
  • 34,219
  • 14
  • 75
  • 100
  • Thanks for tips! I completely agree with you about UA sniffing. In this case, I'm writing a jQuery plugin and I would like to avoid having Modernizr as a dependency. OTOH, I really really appreciate you providing a code example (+1). Coincidentally, I'm currently using a slightly modified version of [this Modernizr code](https://github.com/Modernizr/Modernizr/blob/master/modernizr.js#L420-446) to detect if it's a `touchstart` or `click` (see edits #1 and #3 in my original question above). – mhulse Jul 12 '12 at 18:32
  • 3
    also don't forget to consider devices such as Microsoft Surface (or many Windows 8 laptops) that have both touch AND mouse, and in the case of Surface a stylus too. i.e. don't *disable* behavior based on 'touch' existing without careful thought – Simon_Weaver Sep 16 '14 at 15:10
12

This may work for you:

var clickEvent = ((document.ontouchstart!==null)?'click':'touchstart');
$("#mylink").on(clickEvent, myClickHandler);
Sky Yip
  • 1,059
  • 12
  • 10
9

Both iOS and Android have touch events, but Windows uses MSPointer events in IE. If you want a cross-device solution, try pointer.js or learn from it:

https://github.com/borismus/pointer.js

Cat Chen
  • 2,387
  • 17
  • 12
  • Interesting! Thanks for the tips and help; I'm checking out the code now. – mhulse Jul 16 '12 at 07:18
  • It looks like pointer.js is now deprecated in favor of this pointer events polyfill https://github.com/jquery/PEP (based on W3 pointer events standard). – Devon Sams Aug 27 '15 at 12:55