What's the best way to detect a 'touch screen' device using JavaScript?
Asked Answered
P

38

530

I've written a jQuery plug-in that's for use on both desktop and mobile devices. I wondered if there is a way with JavaScript to detect if the device has touch screen capability. I'm using jquery-mobile.js to detect the touch screen events and it works on iOS, Android etc., but I'd also like to write conditional statements based on whether the user's device has a touch screen.

Is that possible?

Peria answered 27/1, 2011 at 13:39 Comment(2)
this is the better way var x = 'touchstart' in document.documentElement; console.log(x) // return true if is supported // else return falseStaal
Why is this thread protected if new techniques are still emerging?Gaea
F
141

Update: Please read blmstr's answer below before pulling a whole feature detection library into your project. Detecting actual touch support is more complex, and Modernizr only covers a basic use case.

Modernizr is a great, lightweight way to do all kinds of feature detection on any site.

It simply adds classes to the html element for each feature.

You can then target those features easily in CSS and JS. For example:

html.touch div {
    width: 480px;
}

html.no-touch div {
    width: auto;
}

And Javascript (jQuery example):

$('html.touch #popup').hide();
Feltie answered 27/1, 2011 at 18:3 Comment(1)
Modernizr does not test for touch screens. It tests for the existence of touch events in the browser. See the "Misc Tests" section in the docs: modernizr.com/docs/#features-miscWaive
S
864

UPDATE 2021

To see the old answers: check the history. I decided to start on a clean slate as it was getting out of hands when keeping the history in the post.

My original answer said that it could be a good idea to use the same function as Modernizr was using, but that is not valid anymore as they removed the "touchevents" tests on this PR: https://github.com/Modernizr/Modernizr/pull/2432 due to it being a confusing subject.

With that said this should be a fairly ok way of detecting if the browser has "touch capabilities":

function isTouchDevice() {
  return (('ontouchstart' in window) ||
     (navigator.maxTouchPoints > 0) ||
     (navigator.msMaxTouchPoints > 0));
}

But for more advanced use cases far more smarter persons than me have written about this subject, I would recommend reading those articles:

Solubility answered 27/1, 2011 at 17:46 Comment(22)
why you adding not (!) two times and specific reason?Grisons
The double bang casts a value to a boolean, forcing the function to return either true or false. You can read more about it here: #4687083Muddleheaded
This doesn't work with Opera Mobile 10 or Internet Explorer Mobile 6 (Windows Mobile 6.5).Forthright
Opera desktop 12.5 alpha has started to return true, since the recent Windows 8 touch enabled builds.Acrogen
function is_touch_device() { return !!('ontouchstart' in window);} Doesn't work anymore on Chrome 22 :SLeandroleaning
The double NOT (!!) is superfluous as the in operator already evaluates to a boolean.Tangleberry
'onmsgesturechange' is evaluating true even in non-touch devices (PC). window.navigator.msMaxTouchPoints seems to be more accurate. Found it here.Tangleberry
It's evaluating to true on IE10 on Windows 8 even though my screen has no touch sensors. I upgraded my old laptop from Windows 7 to Windows 8.Laurilaurianne
Is it me or Chrome 24 for Windows now include Touch (probably for Windows 8). I think we now have to use : $('#buttonId').bind('touchstart click', function(e){ e.stopPropagation(); e.preventDefault(); //your code here });Hbomb
Careful because IE10 (while a touch device) doesn't support events like ontouchstart ontouchend and ontouchmove as far as I know.Unformed
@Tangleberry Can you recommend an edit to the last update? !!window.navigator.msMaxTouchPoints ??Affront
@James, yes, that should correctly identify if you're dealing with a touch-capable device in IE10 -- if msMaxTouchPoints is defined and is greater than 0. The double not (!!) shouldn't be necessary since the boolean OR operator (||) will return a boolean. One other thing (for everyone) to remember is that for devices like the MS Surface, you don't know which device the user is going to use -- mouse or touchscreen -- so you'll need to handle both.Tangleberry
@Tangleberry Javascript's || operator doesn't force boolean. It returns the value/result of the second operand if the first evaluates to false-ish. Consider: var x = false || 3; // x: 3. Granted, Javascript accurately bends the result of msMaxTouchPoints to a correct result, but if an actual boolean is desired, it should be double-negated: !!navigator.msMaxTouchPoints, or evaluated > 0. That said, your original comment presenting this solution was very helpful. :)Hopper
('ontouchstart' in window) incorrectly returns true on BlackBerry 9300. (navigator.msMaxTouchPoints > 0) incorrectly returns false on iPod TouchThin
Latest update on this post returns true on IE10 desktop windows!Heavyhanded
IE11 returns false positiveKarisa
with app spacedesk, I use my phone as a second screen to my PC. I can touch phone to browser web, so traditional way can not detect touch screen. use event listener is ok for my situatin: window.addEventListener('touchstart'Stannum
Stupid/basic question alert: How do you use this? It doesn't return true or false for me instead it returns... (){return"ontouchstart"in window||navigator.maxTouchPoints>0||navigator.msMaxTouchPoints>0} Even if I write it as a conditional i statement, it returns the same thing?Acaroid
You should add the whole code of the function isTouchDevice in your script, then you can call this function that will return a boolean eg : if (isTouchDevice()) { ... code for a touch device...} else { ...code for old device... }Handler
on Chrome evaluates to true on desktop. I think, top line should be ('ontouchstart' in window && window.ontouchstart !== null) because window.ontouchstart is nullPimp
The Stu Cox link goes to a "parked domain" page.Deangelo
It's a shame you couldn't simply detect for the absence of a mouse pointer movement rather than having to detect touch events. If the user is on a touch device, you'd assume there's some way to identify if their cursor has even moved around the place before anything was clicked.... eg.. if(mousepointer X Y = 0,0) then, unless we just clicked on something at exactly 0,0 it's probably a device without a mouse pointer...Alburnum
K
144

Since the introduction of interaction media features you simply can do:

if(window.matchMedia("(pointer: coarse)").matches) {
    // touchscreen
}

https://www.w3.org/TR/mediaqueries-4/#descdef-media-any-pointer

Update (due to comments): The above solution is to detect if a "coarse pointer" - usually a touch screen - is the primary input device. In case you want to dectect if a device with e.g. a mouse also has a touch screen you may use any-pointer: coarse instead.

For more information have a look here: Detecting that the browser has no mouse and is touch-only

Knp answered 17/10, 2018 at 12:39 Comment(2)
This is by far the best solution, thank you! Although I would recommend using (pointer: coarse) as you are most likely only targeting the primary input. Can be used in production, since the few unsupporting browsers are desktop only. There is a great article about this on css-tricks.Hexangular
Agreed this is probably the best solution because it takes advantage of a touch detection mechanism which is native to the browsers. I am using it and apparently it works super-well.Audryaudrye
F
141

Update: Please read blmstr's answer below before pulling a whole feature detection library into your project. Detecting actual touch support is more complex, and Modernizr only covers a basic use case.

Modernizr is a great, lightweight way to do all kinds of feature detection on any site.

It simply adds classes to the html element for each feature.

You can then target those features easily in CSS and JS. For example:

html.touch div {
    width: 480px;
}

html.no-touch div {
    width: auto;
}

And Javascript (jQuery example):

$('html.touch #popup').hide();
Feltie answered 27/1, 2011 at 18:3 Comment(1)
Modernizr does not test for touch screens. It tests for the existence of touch events in the browser. See the "Misc Tests" section in the docs: modernizr.com/docs/#features-miscWaive
B
128

As Modernizr doesn't detect IE10 on Windows Phone 8/WinRT, a simple, cross-browser solution is:

var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;

You only ever need to check once as the device won't suddenly support or not support touch, so just store it in a variable so you can use it multiple times more efficiently.

Bibliotherapy answered 20/11, 2012 at 10:10 Comment(0)
C
44

Using all the comments above I've assembled the following code that is working for my needs:

var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));

I have tested this on iPad, Android (Browser and Chrome), Blackberry Playbook, iPhone 4s, Windows Phone 8, IE 10, IE 8, IE 10 (Windows 8 with Touchscreen), Opera, Chrome and Firefox.

It currently fails on Windows Phone 7 and I haven't been able to find a solution for that browser yet.

Hope someone finds this useful.

Calgary answered 15/3, 2013 at 18:36 Comment(5)
Is there any reason you can't use: function is_touch_device() { return !!('ontouchstart' in window) || !!('msmaxtouchpoints' in navigator); };Anamariaanamnesis
using the function will work but I generally like to use the variable method above so it only gets tested once and is faster when I check later on in my code. Also I found that I needed to test to see if msMaxTouchPoints was more than 0 as IE 10 on Windows 8 without a touch screen was returning 0 as msMaxTouchPoints.Calgary
returns true on my Firefox 32 on windows 7 :(Glarum
Firefox 33 and 33.1 on Windows 8 both show false correctly on my system. If you upgrade your Firefox to the latest version does it still return true? Do you maybe have a device installed on your machine that could make Firefox incorrectly think that your machine has touch?Calgary
>>> 'ontouchstart' in window >>> true FF 51.0.1 on ubuntuDelainedelainey
T
25

I like this one:

function isTouchDevice(){
    return window.ontouchstart !== undefined;
}

alert(isTouchDevice());
Templin answered 21/3, 2012 at 12:19 Comment(6)
There is no need to use a ternary expression to return a boolean. Simply use the expression to return the boolean. function isTouchDevice(){ return (window.ontouchstart !== undefined); }Godewyn
You could also just use: var isTouch = 'ontouchstart' in window;, however this does not work with latest Chrome(v31), var isTouch = 'createTouch' in window.document; is still working.Sverdlovsk
As already mentioned in the comments of the previously accepted question. "Modernizr does not test for touch screens. It tests for the existence of touch events in the browser". Your function is technically hasTouchEvents() not isTouchDevice()Agrippina
Note that similar methods testing only touchstart will fail to recognize Surface as a touch device because IE uses pointer events instead.Teshatesla
this function returns TRUE in FF 27.0.1 on windows 8.1 desktop pc (without touch screen).Hermelindahermeneutic
Maybe @Hermelindahermeneutic was right, but in Firefox 39, it correctly returns false.Lalitta
D
20

If you use Modernizr, it is very easy to use Modernizr.touch as mentioned earlier.

However, I prefer using a combination of Modernizr.touch and user agent testing, just to be safe.

var deviceAgent = navigator.userAgent.toLowerCase();

var isTouchDevice = Modernizr.touch || 
(deviceAgent.match(/(iphone|ipod|ipad)/) ||
deviceAgent.match(/(android)/)  || 
deviceAgent.match(/(iemobile)/) || 
deviceAgent.match(/iphone/i) || 
deviceAgent.match(/ipad/i) || 
deviceAgent.match(/ipod/i) || 
deviceAgent.match(/blackberry/i) || 
deviceAgent.match(/bada/i));

if (isTouchDevice) {
        //Do something touchy
    } else {
        //Can't touch this
    }

If you don't use Modernizr, you can simply replace the Modernizr.touch function above with ('ontouchstart' in document.documentElement)

Also note that testing the user agent iemobile will give you broader range of detected Microsoft mobile devices than Windows Phone.

Also see this SO question

Decrescent answered 26/6, 2013 at 16:18 Comment(1)
Lots of bonus points for "do something touchy" and "can't touch this"Blather
P
16

We tried the modernizr implementation, but detecting the touch events is not consistent anymore (IE 10 has touch events on windows desktop, IE 11 works, because the've dropped touch events and added pointer api).

So we decided to optimize the website as a touch site as long as we don't know what input type the user has. This is more reliable than any other solution.

Our researches say, that most desktop users move with their mouse over the screen before they click, so we can detect them and change the behaviour before they are able to click or hover anything.

This is a simplified version of our code:

var isTouch = true;
window.addEventListener('mousemove', function mouseMoveDetector() {
    isTouch = false;
    window.removeEventListener('mousemove', mouseMoveDetector);
});
Peignoir answered 4/7, 2014 at 7:2 Comment(0)
F
14

There is something better than checking if they have a touchScreen, is to check if they are using it, plus that's easier to check.

if (window.addEventListener) {
    var once = false;
    window.addEventListener('touchstart', function(){
        if (!once) {
            once = true;
            // Do what you need for touch-screens only
        }
    });
}
Favourite answered 29/6, 2015 at 1:33 Comment(0)
T
9

Working Fiddle

I have achieved it like this;

function isTouchDevice(){
    return true == ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch);
}

if(isTouchDevice()===true) {
    alert('Touch Device'); //your logic for touch device
}
else {
    alert('Not a Touch Device'); //your logic for non touch device
}
Tragus answered 22/9, 2014 at 6:20 Comment(0)
S
8

This one works well even in Windows Surface tablets !!!

function detectTouchSupport {
msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture,
touchSupport = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch &&     document instanceof DocumentTouch);
if(touchSupport) {
    $("html").addClass("ci_touch");
}
else {
    $("html").addClass("ci_no_touch");
}
}
Selda answered 10/10, 2013 at 15:27 Comment(0)
G
7

The biggest "gotcha" with trying to detect touch is on hybrid devices that support both touch and the trackpad/mouse. Even if you're able to correctly detect whether the user's device supports touch, what you really need to do is detect what input device the user is currently using. There's a detailed write up of this challenge and a possible solution here.

Basically the approach to figuring out whether a user just touched the screen or used a mouse/ trackpad instead is to register both a touchstart and mouseover event on the page:

document.addEventListener('touchstart', functionref, false) // on user tap, "touchstart" fires first
document.addEventListener('mouseover', functionref, false) // followed by mouse event, ie: "mouseover"

A touch action will trigger both of these events, though the former (touchstart) always first on most devices. So counting on this predictable sequence of events, you can create a mechanism that dynamically adds or removes a can-touch class to the document root to reflect the current input type of the user at this moment on the document:

;(function(){
    var isTouch = false //var to indicate current input type (is touch versus no touch) 
    var isTouchTimer 
    var curRootClass = '' //var indicating current document root class ("can-touch" or "")
     
    function addtouchclass(e){
        clearTimeout(isTouchTimer)
        isTouch = true
        if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present
            curRootClass = 'can-touch'
            document.documentElement.classList.add(curRootClass)
        }
        isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event
    }
     
    function removetouchclass(e){
        if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present
            isTouch = false
            curRootClass = ''
            document.documentElement.classList.remove('can-touch')
        }
    }
     
    document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch
    document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad
})();

More details here.

Germiston answered 23/10, 2016 at 20:26 Comment(0)
C
7

I think the best method is:

var isTouchDevice =
    (('ontouchstart' in window) ||
    (navigator.maxTouchPoints > 0) ||
    (navigator.msMaxTouchPoints > 0));
if(!isTouchDevice){
    /* Code for touch device /*
}else{
    /* Code for non touch device */
}
Creosol answered 28/5, 2019 at 12:34 Comment(1)
navigator.MaxTouchPoints -> navigator.maxTouchPointsLemuelah
G
6

I used pieces of the code above to detect whether touch, so my fancybox iframes would show up on desktop computers and not on touch. I noticed that Opera Mini for Android 4.0 was still registering as a non-touch device when using blmstr's code alone. (Does anyone know why?)

I ended up using:

<script>
$(document).ready(function() {
    var ua = navigator.userAgent;
    function is_touch_device() { 
        try {  
            document.createEvent("TouchEvent");  
            return true;  
        } catch (e) {  
            return false;  
        }  
    }

    if ((is_touch_device()) || ua.match(/(iPhone|iPod|iPad)/) 
    || ua.match(/BlackBerry/) || ua.match(/Android/)) {
        // Touch browser
    } else {
        // Lightbox code
    }
});
</script>
Geiger answered 12/1, 2012 at 20:58 Comment(2)
could you please explain, why you do not to use a single match call with a single regexp /iPhone|iPod|iPad|Android|BlackBerry/ ?Footslog
Opera Mini carries out rendering on Opera's servers and not on the device itself, so it's kinda weird that way.Spiccato
S
6

Actually, I researched this question and consider all situations. because it is a big issue on my project too. So I reach the below function, it works for all versions of all browsers on all devices:

const isTouchDevice = () => {
  const prefixes = ['', '-webkit-', '-moz-', '-o-', '-ms-', ''];
  const mq = query => window.matchMedia(query).matches;

  if (
    'ontouchstart' in window ||
    (window.DocumentTouch && document instanceof DocumentTouch)
  ) {
    return true;
  }
  return mq(['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''));
};

Hint: Definitely, the isTouchDevice just returns boolean values.

Sower answered 20/2, 2020 at 2:20 Comment(2)
I think you need const IsTouchDevice = ( () => { ... } )();Initial
@Rob, it is a function, it's on the developer to how to use it.Sower
G
5

Check out this post, it gives a really nice code snippet for what to do when touch devices are detected or what to do if touchstart event is called:

$(function(){
  if(window.Touch) {
    touch_detect.auto_detected();
  } else {
    document.ontouchstart = touch_detect.surface;
  }
}); // End loaded jQuery
var touch_detect = {
  auto_detected: function(event){
    /* add everything you want to do onLoad here (eg. activating hover controls) */
    alert('this was auto detected');
    activateTouchArea();
  },
  surface: function(event){
    /* add everything you want to do ontouchstart here (eg. drag & drop) - you can fire this in both places */
    alert('this was detected by touching');
    activateTouchArea();
  }
}; // touch_detect
function activateTouchArea(){
  /* make sure our screen doesn't scroll when we move the "touchable area" */
  var element = document.getElementById('element_id');
  element.addEventListener("touchstart", touchStart, false);
}
function touchStart(event) {
  /* modularize preventing the default behavior so we can use it again */
  event.preventDefault();
}
Grisons answered 22/12, 2011 at 22:42 Comment(0)
C
5

I would avoid using screen width to determine if a device is a touch device. There are touch screens much larger than 699px, think of Windows 8. Navigatior.userAgent may be nice to override false postives.

I would recommend checking out this issue on Modernizr.

Are you wanting to test if the device supports touch events or is a touch device. Unfortunately, that's not the same thing.

Coming answered 16/12, 2012 at 1:47 Comment(0)
M
5

Many of these work but either require jQuery, or javascript linters complain about the syntax. Considering your initial question asks for a "JavaScript" (not jQuery, not Modernizr) way of solving this, here's a simple function that works every time. It's also about as minimal as you can get.

function isTouchDevice() {
    return !!window.ontouchstart;
}

console.log(isTouchDevice());

One last benefit I'll mention is that this code is framework and device agnostic. Enjoy!

Mohandis answered 7/10, 2014 at 21:28 Comment(0)
O
5

No, it's not possible. The excellent answers given are only ever partial, because any given method will produce false positives and false negatives. Even the browser doesn't always know if a touchscreen is present, due to OS APIs, and the fact can change during a browser session, particularly with KVM-type arrangements.

See further details in this excellent article:

http://www.stucox.com/blog/you-cant-detect-a-touchscreen/

The article suggests you reconsider the assumptions that make you want to detect touchscreens, they're probably wrong. (I checked my own for my app, and my assumptions were indeed wrong!)

The article concludes:

For layouts, assume everyone has a touchscreen. Mouse users can use large UI controls much more easily than touch users can use small ones. The same goes for hover states.

For events and interactions, assume anyone may have a touchscreen. Implement keyboard, mouse and touch interactions alongside each other, ensuring none block each other.

Oblige answered 16/12, 2014 at 3:11 Comment(0)
C
5

Right so there is a huge debate over detecting touch/non-touch devices. The number of window tablets and the size of tablets is increasing creating another set of headaches for us web developers.

I have used and tested blmstr's answer for a menu. The menu works like this: when the page loads the script detects if this is a touch or non touch device. Based on that the menu would work on hover (non-touch) or on click/tap (touch).

In most of the cases blmstr's scripts seemed to work just fine (specifically the 2018 one). BUT there was still that one device that would be detected as touch when it is not or vice versa.

For this reason I did a bit of digging and thanks to this article I replaced a few lines from blmstr's 4th script into this:

function is_touch_device4() {
    if ("ontouchstart" in window)
        return true;

    if (window.DocumentTouch && document instanceof DocumentTouch)
        return true;


    return window.matchMedia( "(pointer: coarse)" ).matches;
}

alert('Is touch device: '+is_touch_device4());
console.log('Is touch device: '+is_touch_device4());

Because of the lockdown have a limited supply of touch devices to test this one but so far the above works great.

I would appreceate if anyone with a desktop touch device (ex. surface tablet) can confirm if script works all right.

Now in terms of support the pointer: coarse media query seems to be supported. I kept the lines above since I had (for some reason) issues on mobile firefox but the lines above the media query do the trick.

Thanks

Corley answered 27/10, 2020 at 12:11 Comment(1)
To catch mobile firefox you can add this to the media query. (-moz-touch-enabled: 1)Paleethnology
H
4

It looks like Chrome 24 now support touch events, probably for Windows 8. So the code posted here no longer works. Instead of trying to detect if touch is supported by the browser, I'm now binding both touch and click events and making sure only one is called:

myCustomBind = function(controlName, callback) {

  $(controlName).bind('touchend click', function(e) {
    e.stopPropagation();
    e.preventDefault();

    callback.call();
  });
};

And then calling it:

myCustomBind('#mnuRealtime', function () { ... });

Hope this helps !

Hbomb answered 1/2, 2013 at 17:43 Comment(1)
Related thread, #12566806Normally
C
4

All browser supported except Firefox for desktop always TRUE because of Firefox for desktop support responsive design for developer even you click Touch-Button or not!

I hope Mozilla will fix this in next version.

I'm using Firefox 28 desktop.

function isTouch()
{
    return !!("ontouchstart" in window) || !!(navigator.msMaxTouchPoints);
}
Chessman answered 11/4, 2014 at 4:26 Comment(1)
it's still version 32.0 and they haven't fixed it yet! insane. why can't this be toggable?? This always returns true :(Glarum
F
4

jQuery v1.11.3

There is a lot of good information in the answers provided. But, recently I spent a lot of time trying to actually tie everything together into a working solution for the accomplishing two things:

  1. Detect that the device in use is a touch screen type device.
  2. Detect that the device was tapped.

Besides this post and Detecting touch screen devices with Javascript, I found this post by Patrick Lauke extremely helpful: https://hacks.mozilla.org/2013/04/detecting-touch-its-the-why-not-the-how/

Here is the code...

$(document).ready(function() {
//The page is "ready" and the document can be manipulated.

    if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0))
    {
      //If the device is a touch capable device, then...
      $(document).on("touchstart", "a", function() {

        //Do something on tap.

      });
    }
    else
    {
      null;
    }
});

Important! The *.on( events [, selector ] [, data ], handler ) method needs to have a selector, usually an element, that can handle the "touchstart" event, or any other like event associated with touches. In this case, it is the hyperlink element "a".

Now, you don't need to handle the regular mouse clicking in JavaScript, because you can use CSS to handle these events using selectors for the hyperlink "a" element like so:

/* unvisited link */
a:link 
{

}

/* visited link */
a:visited 
{

}

/* mouse over link */
a:hover 
{

}

/* selected link */
a:active 
{

}

Note: There are other selectors as well...

Foggia answered 28/11, 2015 at 20:55 Comment(0)
P
4

The problem

Due to hybrid devices which use a combination of touch and mouse input, you need to be able dynamically change the state / variable which controls whether a piece of code should run if the user is a touch user or not.

Touch devices also fire mousemove on tap.

Solution

  1. Assume touch is false on load.
  2. Wait until a touchstart event is fired, then set it to true.
  3. If touchstart was fired, add a mousemove handler.
  4. If the time between two mousemove events firing was less than 20ms, assume they are using a mouse as input. Remove the event as it's no longer needed and mousemove is an expensive event for mouse devices.
  5. As soon as touchstart is fired again (user went back to using touch), the variable is set back to true. And repeat the process so it's determined in a dynamic fashion. If by some miracle mousemove gets fired twice on touch absurdly quickly (in my testing it's virtually impossible to do it within 20ms), the next touchstart will set it back to true.

Tested on Safari iOS and Chrome for Android.

Note: not 100% sure on the pointer-events for MS Surface, etc.

Codepen demo


const supportsTouch = 'ontouchstart' in window;
let isUsingTouch = false;

// `touchstart`, `pointerdown`
const touchHandler = () => {
  isUsingTouch = true;
  document.addEventListener('mousemove', mousemoveHandler);
};

// use a simple closure to store previous time as internal state
const mousemoveHandler = (() => {
  let time;
  
  return () => {
    const now = performance.now();

    if (now - time < 20) {
      isUsingTouch = false;
      document.removeEventListener('mousemove', mousemoveHandler);
    }

    time = now;
  }
})();

// add listeners
if (supportsTouch) {
  document.addEventListener('touchstart', touchHandler);
} else if (navigator.maxTouchPoints || navigator.msMaxTouchPoints) {
  document.addEventListener('pointerdown', touchHandler);
}
Phidippides answered 17/6, 2017 at 8:49 Comment(0)
S
3
var isTouchScreen = 'createTouch' in document;

or

var isTouchScreen = 'createTouch' in document || screen.width <= 699 || 
    ua.match(/(iPhone|iPod|iPad)/) || ua.match(/BlackBerry/) || 
    ua.match(/Android/);

would be a more thorough check I suppose.

Selfexpression answered 2/11, 2011 at 20:5 Comment(1)
It would be good to note that ua refers to navigator.userAgent. Also the detection by screen width can give false result if someone opens a browser in not full screen mode.Venegas
F
3

I use:

if(jQuery.support.touch){
    alert('Touch enabled');
}

in jQuery mobile 1.0.1

Fredericton answered 19/3, 2012 at 14:11 Comment(0)
C
3

You can install modernizer and use a simple touch event. This is very effective and works on every device I have tested it on including windows surface!

I've created a jsFiddle

function isTouchDevice(){
    if(Modernizr.hasEvent('touchstart') || navigator.userAgent.search(/Touch/i) != -1){
         alert("is touch");
            return true;
         }else{
            alert("is not touch");
            return false;
    }
}
Capriccio answered 21/5, 2014 at 8:37 Comment(1)
Welcome to SO! Code by itself (like uncommented code) rarely constitutes an answer. You could improve this answer by adding an explanation of the snippet.Julenejulep
S
2

I also struggled a lot with different options on how to detect in Javascript whether the page is displayed on a touch screen device or not. IMO, as of now, no real option exists to detect the option properly. Browsers either report touch events on desktop machines (because the OS maybe touch-ready), or some solutions don't work on all mobile devices.

In the end, I realized that I was following the wrong approach from the start: If my page was to look similar on touch and non-touch devices, I maybe shouldn't have to worry about detecting the property at all: My scenario was to deactivate tooltips over buttons on touch devices as they lead to double-taps where I wanted a single tap to activate the button.

My solution was to refactor the view so that no tooltip was needed over a button, and in the end I didn't need to detect the touch device from Javascript with methods that all have their drawbacks.

Scraggy answered 20/5, 2014 at 9:13 Comment(0)
P
2

The practical answer seems to be one that considers the context:

1) Public site (no login)
Code the UI to work with both options together.

2) Login site
Capture whether a mouse-move occurred on the login form, and save this into a hidden input. The value is passed with the login credentials and added to the user's session, so it can be used for the duration of the session.

Jquery to add to login page only:

$('#istouch').val(1); // <-- value will be submitted with login form

if (window.addEventListener) {
    window.addEventListener('mousemove', function mouseMoveListener(){
        // Update hidden input value to false, and stop listening
        $('#istouch').val(0); 
        window.removeEventListener('mousemove', mouseMoveListener);
    });
} 

(+1 to @Dave Burt and +1 to @Martin Lantzsch on their answers)

Personalism answered 9/7, 2015 at 19:6 Comment(0)
G
0

Extent jQuery support object:

jQuery.support.touch = 'ontouchend' in document;

And now you can check it anywhere, like this:

if( jQuery.support.touch )
   // do touch stuff
Glarum answered 19/2, 2014 at 16:50 Comment(0)
C
0

This seems to be working fine for me so far:

//Checks if a touch screen
is_touch_screen = 'ontouchstart' in document.documentElement;

if (is_touch_screen) {
  // Do something if a touch screen
}
else {
  // Not a touch screen (i.e. desktop)
}
Chromophore answered 6/12, 2015 at 20:45 Comment(0)
B
0

When a mouse is attached, it can be assumed with fairly high hitrate (I would say practially 100%) that the user moves the mouse at least a tiny distance after page is ready - without any clicking. The mechanism below detects this. If detected, I consider this as a sign of missing touch support or, if supported, of minor importance when a mouse is in use. Touch-device is assumed if not detected.

EDIT This approach may not fit all purposes. It can be used to control functionality that is activated based on user interaction on the loaded page, for instance an image viewer. The code below will also leave the mousemove event bound on devices without mouse as it stands out now. Other approaches may be better.

Roughly, it goes like this (sorry for jQuery, but similar in pure Javascript):

var mousedown, first, second = false;
var ticks = 10;
$(document).on('mousemove', (function(e) {
    if(UI.mousechecked) return;
    if(!first) {
        first = e.pageX;
        return;
        }
    if(!second && ticks-- === 0) {
        second = e.pageX;
        $(document).off('mousemove'); // or bind it to somewhat else
        }
    if(first  && second  && first !== second && !mousedown){
        // set whatever flags you want
        UI.hasmouse = true;
        UI.touch = false;
        UI.mousechecked = true;
    }

    return;
}));
$(document).one('mousedown', (function(e) {
    mousedown = true;
    return;
}));
$(document).one('mouseup', (function(e) {
    mousedown = false;
    return;
}));
Bullwhip answered 4/10, 2016 at 15:8 Comment(0)
I
0

You can use the following code:

function isTouchDevice() {
   var el = document.createElement('div');
   el.setAttribute('ongesturestart', 'return;'); // or try "ontouchstart"
   return typeof el.ongesturestart === "function";
}

Source: Detecting touch-based browsing and @mplungjan post.

The above solution was based on detecting event support without browser sniffing article.

You can check the results at the following test page.

Please note that the above code tests only whether the browser has support for touch, not the device. So if you've laptop with touch-screen, your browser may not have the support for the touch events. The recent Chrome supports touch events, but other browser may not.

You could also try:

if (document.documentElement.ontouchmove) {
  // ...
}

but it may not work on iPhone devices.

Interfaith answered 17/7, 2017 at 15:57 Comment(0)
P
0

I know it's many years later, but I found a related solution: How to bind ‘touchstart’ and ‘click’ events but not respond to both ?

This jQuery function listens for both the touch and mouse event. Whichever event is fired first disables the second. Here is how I used it to get a div to respond to just one of the two events:

$(".phoneBtn").on( "mousedown touchstart", function(event) {
                      if (event.type == "touchstart") {
                          pressButton(this);
                          $(this).off('mousedown');
                          //Only touchstart event is heard

                      } else if (event.type == "mousedown") {
                          $(this).off('touchstart');
                          pressButton(this);
                          //Only mousedown event is heard
                      } 
                  )}
Persistence answered 29/10, 2023 at 23:51 Comment(0)
M
-2
$.support.touch ? "true" : "false";
Mongo answered 30/8, 2017 at 8:4 Comment(0)
S
-2

it's so simple if you test that touchstart is supported in document.documentElement

var x = 'touchstart' in document.documentElement;
console.log(x)
// return true if is supported
// else return false
Staal answered 22/9, 2017 at 19:8 Comment(0)
E
-3

Although it's only in alpha, the jquery mobile framework is worth checking out. It will normalize these types of events across mobile browsers. Perhaps see what they're doing. I'm assuming jquery-mobile.js is something different than this framework.

Extrusion answered 27/1, 2011 at 17:53 Comment(2)
jquery mobile is great but and we use it for mobile development but I wanted to be able to test specifically for touch screen devices. There didn't seem to be a way of doing that with just jquery mobile.Peria
Right, it doesn't work that way. It uses progressive enhancement.Extrusion
F
-4

this ways works for me, it wait for first user interaction to make sure they're on touch devices

var touchEnabled = false;
$(document.body).one('touchstart',
    function(e){
        touchEnabled=true;
        $(document.documentElement).addClass("touch");
        // other touch related init 
        //
    }
);
Flaxen answered 28/6, 2013 at 23:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.