Qual è il modo migliore per rilevare un dispositivo “touch screen” utilizzando JavaScript?

Ho scritto un plug-in jQuery che può essere utilizzato su entrambi i dispositivi desktop e mobili. Mi sono chiesto se c’è un modo con JavaScript per rilevare se il dispositivo ha funzionalità touchscreen. Sto usando jquery-mobile.js per rilevare gli eventi touch screen e funziona su iOS, Android ecc., Ma mi piacerebbe anche scrivere affermazioni condizionali basate sul fatto che il dispositivo dell’utente abbia un touch screen.

È ansible?

Aggiornamento: leggere la risposta di blmstr di seguito prima di inserire un’intera libreria di rilevamento delle funzionalità nel progetto. Rilevare il supporto tattile effettivo è più complesso e Modernizr copre solo un caso d’uso di base.

Modernizr è un modo eccezionale e leggero per eseguire qualsiasi tipo di rilevamento di funzionalità su qualsiasi sito.

Semplicemente aggiunge classi all’elemento html per ogni funzione.

È quindi ansible indirizzare queste caratteristiche facilmente in CSS e JS. Per esempio:

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

E Javascript (esempio di jQuery):

 $('html.touch #popup').hide(); 

Hai provato a utilizzare questa funzione? (Questo è lo stesso usato da Modernizr.)

 function is_touch_device() { try { document.createEvent("TouchEvent"); return true; } catch (e) { return false; } } 

AGGIORNAMENTO 1

document.createEvent("TouchEvent") ha iniziato a restituire true nell’ultimo chrome (v.17). Modernizr lo ha aggiornato qualche tempo fa. Controlla il test di Modernizr qui .

Aggiorna la tua funzione in questo modo per farlo funzionare:

 function is_touch_device() { return 'ontouchstart' in window; } 

AGGIORNAMENTO 2

Ho scoperto che quanto sopra non funzionava su IE10 (restituendo false su MS Surface). Ecco la soluzione:

 function is_touch_device() { return 'ontouchstart' in window // works on most browsers || 'onmsgesturechange' in window; // works on IE10 with some false positives }; 

AGGIORNAMENTO 3

'onmsgesturechange' in window restituirà true in alcune versioni desktop di IE quindi non è affidabile. Funziona in modo leggermente più affidabile:

 function is_touch_device() { return 'ontouchstart' in window // works on most browsers || navigator.maxTouchPoints; // works on IE10/11 and Surface }; 

AGGIORNAMENTO 2018

Il tempo passa e ci sono modi nuovi e migliori per testare questo. Ho sostanzialmente estratto e semplificato il modo in cui Modernizr lo controlla:

 function is_touch_device() { var prefixes = ' -webkit- -moz- -o- -ms- '.split(' '); var mq = function(query) { return window.matchMedia(query).matches; } if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { return true; } // include the 'heartz' as a way to have a non matching MQ to help terminate the join // https://git.io/vznFH var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''); return mq(query); } 

Qui stanno usando la funzione di query multimediale touch-enabled non standard, che ritengo sia piuttosto strana e ctriggers. Ma hey, nel mondo reale credo che funzioni. In futuro (quando sono supportati da tutti) quelle funzionalità di media query potrebbero fornire gli stessi risultati: pointer e hover .

Scopri la fonte di come Modernizr lo sta facendo .

Per un buon articolo che spiega i problemi con il rilevamento del touch, vedere: Stu Cox: non è ansible rilevare un touchscreen .

Poiché Modernizr non rileva IE10 su Windows Phone 8 / WinRT, una semplice soluzione cross-browser è:

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

Devi solo controllare una volta sola, in quanto il dispositivo non supporterà improvvisamente o non supporta il touch, quindi salvalo in una variabile in modo da poterlo utilizzare più volte in modo più efficiente.

Usando tutti i commenti sopra ho assemblato il seguente codice che funziona per le mie esigenze:

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

Ho testato questo su iPad, Android (Browser e Chrome), Blackberry Playbook, iPhone 4s, Windows Phone 8, IE 10, IE 8, IE 10 (Windows 8 con touchscreen), Opera, Chrome e Firefox.

Attualmente non funziona su Windows Phone 7 e non sono ancora riuscito a trovare una soluzione per quel browser.

Spero che qualcuno lo ritenga utile.

Mi piace questa:

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

Se usi Modernizr , è molto facile usare Modernizr.touch come accennato in precedenza.

Tuttavia, preferisco usare una combinazione di Modernizr.touch e test degli user-agent, solo per sicurezza.

 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 } 

Se non usi Modernizr, puoi semplicemente sostituire la funzione Modernizr.touch alto con ('ontouchstart' in document.documentElement)

Tieni inoltre presente che testando l’agente utente iemobile ti fornirà una gamma più ampia di dispositivi mobili Microsoft rilevati rispetto a Windows Phone .

Vedi anche questa domanda SO

Abbiamo provato l’implementazione di modernizr, ma il rilevamento degli eventi di touch non è più coerente (IE 10 ha eventi di touch su Windows Desktop, IE 11 funziona, perché ha abbandonato gli eventi di touch e ha aggiunto l’API del puntatore).

Pertanto, abbiamo deciso di ottimizzare il sito Web come sito tattile, purché non conosciamo il tipo di input dell’utente. Questo è più affidabile di qualsiasi altra soluzione.

Le nostre ricerche dicono che la maggior parte degli utenti desktop si sposta con il mouse sullo schermo prima di fare clic, in modo da poterli rilevare e modificare il comportamento prima che siano in grado di fare clic o passare il mouse su qualsiasi cosa.

Questa è una versione semplificata del nostro codice:

 var isTouch = true; window.addEventListener('mousemove', function mouseMoveDetector() { isTouch = false; window.removeEventListener('mousemove', mouseMoveDetector); }); 

C’è qualcosa di meglio che controllare se hanno un touchScreen, è quello di verificare se lo stanno usando, in più è più facile da controllare.

 if (window.addEventListener) { var once = false; window.addEventListener('touchstart', function(){ if (!once) { once = true; // Do what you need for touch-screens only } }); } 

Fiddle che lavora

L’ho raggiunto in questo modo;

 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 } 

Questo funziona bene anche su tablet Windows Surface !!!

 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"); } } 

Ho usato pezzi del codice di cui sopra per rilevare se touch, quindi i miei iframes di fancybox venivano visualizzati sui computer desktop e non sul touch. Ho notato che Opera Mini per Android 4.0 stava ancora registrando come dispositivo non-touch quando si utilizza il solo codice di blmstr. (Qualcuno sa perché?)

Ho finito per usare:

  

Il più grande “trucco” con il tentativo di rilevare il touch è su dispositivi ibridi che supportano sia il touch che il trackpad / mouse. Anche se sei in grado di rilevare correttamente se il dispositivo dell’utente supporta il touch, ciò che devi realmente fare è rilevare il dispositivo di input che l’utente sta attualmente utilizzando. C’è una descrizione dettagliata di questa sfida e una ansible soluzione qui .

Fondamentalmente l’approccio per capire se un utente ha appena sfiorato lo schermo o utilizzato un mouse / trackpad è invece quello di registrare entrambi gli touchstart e mouseover sulla pagina:

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

Un’azione touch attiverà entrambi questi eventi, sebbene il primo ( touchstart ) sia sempre il primo sulla maggior parte dei dispositivi. Quindi, contando su questa prevedibile sequenza di eventi, è ansible creare un meccanismo che aggiunge o rimuove dynamicmente una class can-touch alla radice del documento per riflettere il tipo di input corrente dell’utente in questo momento sul documento:

 ;(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 })(); 

Maggiori dettagli qui .

Dai un’occhiata a questo post , fornisce uno snippet di codice veramente bello su cosa fare quando vengono rilevati dispositivi touch o cosa fare se viene chiamato l’evento touchstart:

 $(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(); } 

Eviterei di usare la larghezza dello schermo per determinare se un dispositivo è un dispositivo touch. Ci sono touch screen molto più grandi di 699px, pensate a Windows 8. Navigatior.userAgent può essere utile per sovrascrivere i falsi postivi.

Consiglierei di dare un’occhiata a questo problema su Modernizr.

Stai cercando di verificare se il dispositivo supporta gli eventi touch o è un dispositivo touch. Sfortunatamente, non è la stessa cosa.

No, non è ansible. Le risposte eccellenti fornite sono sempre parziali, perché ogni metodo dato produrrà falsi positivi e falsi negativi. Anche il browser non sa sempre se è presente un touchscreen, a causa delle API del sistema operativo, e il fatto può cambiare durante una sessione del browser, in particolare con gli arrangiamenti di tipo KVM.

Vedi ulteriori dettagli in questo eccellente articolo:

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

L’articolo suggerisce di riconsiderare le ipotesi che ti fanno venir voglia di rilevare i touchscreen, probabilmente si sbagliano. (Ho controllato il mio per la mia app, e le mie supposizioni erano davvero sbagliate!)

L’articolo conclude:

Per i layout, supponiamo che tutti abbiano un touchscreen. Gli utenti di mouse possono utilizzare controlli UI di grandi dimensioni in modo molto più semplice rispetto a quelli con touch che possono utilizzare quelli piccoli. Lo stesso vale per gli stati hover.

Per eventi e interazioni, supponi che qualcuno possa avere un touchscreen. Implementa le interazioni tra tastiera, mouse e touch l’una accanto all’altra, assicurandosi che nessuna si blocchi l’una con l’altra.

Sembra che Chrome 24 ora supporti gli eventi touch, probabilmente per Windows 8. Quindi il codice pubblicato qui non funziona più. Invece di provare a rilevare se il touch è supportato dal browser, ora lego gli eventi touch e click e mi assicuro che ne venga chiamato solo uno:

 myCustomBind = function(controlName, callback) { $(controlName).bind('touchend click', function(e) { e.stopPropagation(); e.preventDefault(); callback.call(); }); }; 

E poi chiamandolo:

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

Spero che questo ti aiuti !

 var isTouchScreen = 'createTouch' in document; 

o

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

sarebbe un controllo più approfondito, suppongo.

Io uso:

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

in jQuery Mobile 1.0.1

Tutti i browser supportati tranne Firefox per desktop sempre VERO a causa di Firefox per il supporto del desktop design reattivo per lo sviluppatore anche se si fa clic su Touch-Button o no!

Spero che Mozilla risolverà questo nella prossima versione.

Sto usando il desktop di Firefox 28.

 function isTouch() { return !!("ontouchstart" in window) || !!(navigator.msMaxTouchPoints); } 

Ho anche faticato parecchio con diverse opzioni su come rilevare in Javascript se la pagina è visualizzata su un dispositivo touch screen o meno. IMO, al momento, non esiste alcuna opzione reale per rilevare correttamente l’opzione. I browser o riportano gli eventi di touch sui computer desktop (perché il sistema operativo è forse pronto per il touch) oppure alcune soluzioni non funzionano su tutti i dispositivi mobili.

Alla fine, mi sono reso conto che stavo seguendo l’approccio sbagliato dall’inizio: se la mia pagina dovesse apparire simile sui dispositivi touch e non-touch, forse non dovrei preoccuparmi di rilevare la proprietà del tutto: il mio scenario era per distriggersre le descrizioni dei comandi sui pulsanti dei dispositivi touch in quanto portano a toccare due volte dove volevo un singolo touch per triggersre il pulsante.

La mia soluzione era quella di ridefinire la vista in modo che non fosse necessario alcun suggerimento su un pulsante, e alla fine non avevo bisogno di rilevare il dispositivo touch da Javascript con metodi che hanno tutti i loro svantaggi .

È ansible installare il modernizzatore e utilizzare un semplice evento di touch. Questo è molto efficace e funziona su tutti i dispositivi su cui ho provato, inclusa la superficie di Windows!

Ho creato un 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; } } 

La risposta pratica sembra essere quella che considera il contesto:

1) Sito pubblico (nessun login)
Codifica l’interfaccia utente per lavorare insieme con entrambe le opzioni.

2) Accedi al sito
Cattura se si è verificato uno spostamento del mouse nel modulo di accesso e salvalo in un input nascosto. Il valore viene passato con le credenziali di accesso e aggiunto alla sessione dell’utente, quindi può essere utilizzato per la durata della sessione.

Jquery da aggiungere solo alla pagina di accesso:

 $('#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 a @Dave Burt e +1 a @Martin Lantzsch sulle loro risposte)

jQuery v1.11.3

Ci sono molte buone informazioni nelle risposte fornite. Ma, di recente, ho passato molto tempo a cercare di bind tutto insieme in una soluzione operativa per realizzare due cose:

  1. Rileva che il dispositivo in uso è un dispositivo di tipo touch screen.
  2. Rileva che il dispositivo è stato toccato.

Oltre a questo post e al rilevamento di dispositivi touch screen con Javascript , ho trovato estremamente utile questo post di Patrick Lauke: https://hacks.mozilla.org/2013/04/detecting-touch-its-the-why-not-the-how /

Ecco il codice …

 $(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; } }); 

Importante! Il metodo *.on( events [, selector ] [, data ], handler ) deve avere un selettore, solitamente un elemento, in grado di gestire l’evento “touchstart” o qualsiasi altro evento simile associato ai tocchi. In questo caso, è l’elemento di collegamento ipertestuale “a”.

Ora, non è necessario gestire il normale clic del mouse in JavaScript, poiché è ansible utilizzare i CSS per gestire questi eventi utilizzando i selettori per l’elemento “a” del collegamento ipertestuale in questo modo:

 /* unvisited link */ a:link { } /* visited link */ a:visited { } /* mouse over link */ a:hover { } /* selected link */ a:active { } 

Nota: ci sono anche altri selettori …

Il problema

A causa di dispositivi ibridi che utilizzano una combinazione di input touch e mouse, è necessario essere in grado di modificare dynamicmente lo stato / variabile che controlla se un pezzo di codice deve essere eseguito se l’utente è un utente touch o meno.

I dispositivi touch consentono anche il mousemove del mousemove alla spina.

Soluzione

  1. Supponiamo che il touch sia falso sul carico.
  2. Attendere fino a quando non viene touchstart un evento touchstart , quindi impostarlo su true.
  3. Se è stato triggersto il touchstart, aggiungi un gestore di mouse in alto.
  4. Se il tempo tra due eventi Mousemove è inferiore a 20 ms, supponiamo che stiano usando un mouse come input. Rimuovi l’evento poiché non è più necessario e mousemove è un evento costoso per i dispositivi mouse.
  5. Non appena viene triggersto nuovamente il touchstart (l’utente è tornato a utilizzare il touch), la variabile viene impostata su true. E ripeti il ​​processo in modo che sia determinato in modo dinamico. Se per qualche miracolo mousemove viene sparato due volte in touch in modo assurdo velocemente (nei miei test è praticamente imansible farlo entro 20 ms), il prossimo touchstart tornerà alla realtà.

Testato su Safari iOS e Chrome per Android.

Nota: non sicuro al 100% sugli eventi puntatore per MS Surface, ecc.

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); } 

Estensione dell’object di support jQuery:

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

E ora puoi controllarlo ovunque, in questo modo:

 if( jQuery.support.touch ) // do touch stuff 

Questo sembra funzionare bene finora per me:

 //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 (ie desktop) } 

Nota rapida per coloro che potrebbero essere tentati di scrivere window.ontouchstart !== undefined -> si prega di utilizzare la risposta micnica, in quanto undefined non è una parola chiave in JavaScript. Grande problema se sviluppare scrive qualcosa come:

 undefined = window.ontouchstart; 

Lo sviluppatore può rendere indefinito tutto ciò che desidera, e puoi anche controllare se window.ontouchstart = myNonExistingWord;

Non mancare di rispetto a chi ha dato questa risposta: sono sicuro di averlo scritto anche nel mio codice;)

Quando un mouse è collegato, può essere assunto con un hitrate piuttosto elevato (direi pragmaticamente al 100%) che l’utente sposta il mouse almeno una piccola distanza dopo che la pagina è pronta, senza alcun clic. Il meccanismo sottostante lo rileva. Se rilevato, lo considero come un segno di supporto touch mancante o, se supportato, di minore importanza quando si utilizza un mouse. Il dispositivo touch è assunto se non rilevato.

EDIT Questo approccio potrebbe non essere adatto a tutti gli scopi. Può essere utilizzato per controllare la funzionalità triggersta in base all’interazione dell’utente nella pagina caricata, ad esempio un visualizzatore di immagini. Il codice qui sotto lascerà anche l’evento mousemove legato ai dispositivi senza mouse, come si nota ora. Altri approcci potrebbero essere migliori.

Approssimativamente, va così (mi dispiace per jQuery, ma simile in puro 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; })); 

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.

Puoi anche provare:

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

but it may not work on iPhone devices.

 $.support.touch ? "true" : "false";