Quelle est la meilleure façon de détecter un appareil à "écran tactile" en utilisant JavaScript?
j'ai écrit un plug-in jQuery qui est destiné à être utilisé sur les appareils de bureau et Mobiles. Je me suis demandé s'il y avait un moyen avec JavaScript pour détecter si l'appareil a la capacité d'écran tactile. Je suis à l'aide de jquery mobile.js pour détecter les événements écran tactile et il fonctionne sur iOS, Android, etc. mais j'aimerais aussi écrire des instructions conditionnelles selon que l'utilisateur de l'appareil dispose d'un écran tactile.
est-ce possible?
30 réponses
mise à Jour: Veuillez lire blmstr la réponse de ci-dessous avant de tirer toute une fonctionnalité de détection de la bibliothèque dans votre projet. La détection de l'appui tactile réel est plus complexe, et Modernizr ne couvre qu'un cas d'utilisation de base.
Modernizr est un excellent moyen, léger de faire toutes sortes de détection des caractéristiques sur n'importe quel site.
Il ajoute simplement des classes à l'élément html pour chaque fonctionnalité.
vous pouvez alors cibler ces caractéristiques facilement dans CSS et JS. Par exemple:
html.touch div {
width: 480px;
}
html.no-touch div {
width: auto;
}
et Javascript (exemple jQuery):
$('html.touch #popup').hide();
avez-vous essayé cette fonction? (C'est le même que Modernizr utilisé pour utiliser.)
function is_touch_device() {
try {
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
}
UPDATE 1
document.createEvent("TouchEvent")
ont commencé à retourner true
dans le dernier chrome (v. 17). Modernizr mis à jour cela il ya un certain temps. Vérifier Modernizr test ici .
mettez à jour votre fonction comme ceci pour la faire fonctionner:
function is_touch_device() {
return 'ontouchstart' in window;
}
UPDATE 2
j'ai trouvé que ce qui précède ne fonctionnait pas sur IE10 (retour de faux sur la surface MS). Voici la solution:
function is_touch_device() {
return 'ontouchstart' in window // works on most browsers
|| 'onmsgesturechange' in window; // works on IE10 with some false positives
};
UPDATE 3
'onmsgesturechange' in window
retournera vrai dans certaines versions de bureau IE donc pas fiable. Cela fonctionne un peu plus sûrement:
function is_touch_device() {
return 'ontouchstart' in window // works on most browsers
|| navigator.maxTouchPoints; // works on IE10/11 and Surface
};
mise à JOUR 2018
le temps passe et il y a de nouvelles et meilleures façons de tester cela. J'ai essentiellement extrait et simplifié la façon de Modernizr de le vérifier:
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);
}
ici, ils utilisent la fonction de requête multimédia non standard touch-enabled
, qui je pense est un peu bizarre et mauvaise pratique. Mais bon, dans le monde réel je suppose que ça marche. Dans le futur (quand ils sont soutenus par tous) ces caractéristiques de requête de médias pourraient vous donner les mêmes résultats: pointer
et hover
.
découvrez les source de la façon dont Modernizr font .
pour un bon article qui explique les problèmes avec la détection de contact, Voir: Stu Cox: vous ne pouvez pas détecter un écran tactile .
comme Modernizr ne détecte pas IE10 sur Windows Phone 8 / WinRT, une solution simple, cross-browser est:
var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;
vous n'avez besoin de vérifier qu'une seule fois car l'appareil ne supporte pas subitement ou ne supporte pas le toucher, alors il suffit de le stocker dans une variable pour que vous puissiez l'utiliser plusieurs fois plus efficacement.
en Utilisant les commentaires ci-dessus, j'ai assemblé le code suivant qui fonctionne pour mes besoins:
var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));
j'ai testé cela sur iPad, Android (Navigateur et Chrome), Blackberry Playbook, iPhone 4s, Windows Phone 8, IE 10, IE 8, IE 10 (Windows 8 Avec Écran Tactile), Opera, Chrome et Firefox.
il échoue actuellement sur Windows Phone 7 et je n'ai pas encore été en mesure de trouver une solution pour ce navigateur.
Hope quelqu'un trouve cela utile.
j'aime celui-ci:
function isTouchDevice(){
return typeof window.ontouchstart !== 'undefined';
}
alert(isTouchDevice());
si vous utilisez Modernizr , il est très facile à utiliser Modernizr.touch
comme mentionné ci-dessus.
cependant, je préfère utiliser une combinaison de Modernizr.touch
et de test d'agent utilisateur, juste pour être sûr.
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
}
si vous n'utilisez pas Modernizr, vous pouvez simplement remplacer la fonction Modernizr.touch
ci-dessus par ('ontouchstart' in document.documentElement)
notez aussi que tester l'agent utilisateur iemobile
vous donnera une plus grande portée des appareils mobiles de Microsoft détectés que Windows Phone
.
nous avons essayé l'implémentation modernizr, mais la détection des événements tactiles n'est plus cohérente (IE 10 a des événements tactiles sur windows desktop, IE 11 fonctionne, parce que les événements tactiles ont été abandonnés et ont ajouté l'api de pointeur).
nous avons donc décidé d'optimiser le site Web en tant que site tactile aussi longtemps que nous ne savons pas quel type d'entrée l'Utilisateur a. Cette solution est plus fiable que toute autre.
nos recherches disent, que la plupart des utilisateurs de bureau se déplacent avec leur la souris sur l'écran avant qu'ils ne cliquent, de sorte que nous pouvons les détecter et changer le comportement avant qu'ils ne soient capables de cliquer ou n'importe quoi.
c'est une version simplifiée de notre code:
var isTouch = true;
window.addEventListener('mousemove', function mouseMoveDetector() {
isTouch = false;
window.removeEventListener('mousemove', mouseMoveDetector);
});
il y a quelque chose de mieux que de vérifier s'ils ont un écran tactile, c'est de vérifier s'ils l'utilisent, et c'est plus facile à vérifier.
if (window.addEventListener) {
var once = false;
window.addEventListener('touchstart', function(){
if (!once) {
once = true;
// Do what you need for touch-screens only
}
});
}
j'ai réalisé comme ceci;
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
}
celui-ci fonctionne bien même dans les tablettes de surface de Windows !!!
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");
}
}
j'ai utilisé des morceaux du code ci-dessus pour détecter si touch, donc mes iframes fancybox apparaîtraient sur les ordinateurs de bureau et pas sur touch. J'ai remarqué que Opera Mini Pour Android 4.0 était toujours enregistré comme un appareil non-tactile en utilisant le code de blmstr seul. (Quelqu'un sait pourquoi?)
j'ai fini par utiliser:
<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>
le plus grand" gotcha " à essayer de détecter le toucher est sur les appareils hybrides qui prennent en charge à la fois le toucher et le trackpad/souris. Même si vous êtes en mesure de détecter correctement si l'appareil de l'utilisateur supporte le toucher, ce que vous devez vraiment faire est de détecter quel périphérique d'entrée l'utilisateur est actuellement en utilisant. Il y a un rapport détaillé de ce défi et une solution possible ici .
fondamentalement l'approche pour comprendre si un utilisateur vient de toucher l'écran ou a utilisé une souris/ trackpad à la place est d'enregistrer à la fois un touchstart
et mouseover
événement sur la page:
document.addEventListener('touchstart', functionref, false) // on user tap, "touchstart" fires first
document.addEventListener('mouseover', functionref, false) // followed by mouse event, ie: "mouseover"
une action tactile déclenchera ces deux événements, bien que le premier ( touchstart
) sera toujours le premier sur la plupart des appareils. Donc, en comptant sur cette séquence prévisible d'événements, vous pouvez créer un mécanisme qui ajoute ou supprime dynamiquement une classe can-touch
à la racine du document pour refléter le courant type d'entrée de l'utilisateur à ce moment sur le 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
})();
plus de détails ici .
découvrez ce post , il donne un très beau fragment de code pour les appareils tactiles sont détectés ou que faire si des évènements touchstart événement est appelé:
$(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();
}
j'éviterais d'utiliser la largeur de l'écran pour déterminer si un appareil est un appareil tactile. Il y a des écrans tactiles beaucoup plus grands que 699px, pensez à Windows 8. Navigatior.userAgent peut être agréable de passer outre les faux positifs.
je voudrais vous recommandons de vérifier cette question sur Modernizr.
voulez-vous tester si l'appareil supporte des événements tactiles ou s'il s'agit d'un appareil tactile. Malheureusement, ce n'est pas la même chose.
non, ce n'est pas possible. Les excellentes réponses données ne sont que partielles, parce que n'importe quelle méthode donnée produira des faux positifs et des faux négatifs. Même le navigateur ne sait pas toujours si un écran tactile est présent, en raison des API OS, et le fait peut changer au cours d'une session de navigateur, en particulier avec des arrangements de type KVM.
Voir plus de détails dans cet excellent article:
http://www.stucox.com/blog/you-cant-detect-a-touchscreen /
l'article vous suggère de reconsidérer les hypothèses qui vous font vouloir détecter les écrans tactiles, ils sont probablement faux. (J'ai vérifié mon propre pour mon application, et mes suppositions étaient en effet fausses!)
l'article conclut:
pour les mises en page, supposez que tout le monde a un écran tactile. Souris les utilisateurs peuvent utiliser les grosses commandes UI sont beaucoup plus faciles que le toucher les utilisateurs peuvent utiliser de petites . Il en va de même pour les états stationnaire.
pour les événements et les interactions, supposez que n'importe qui peut avoir un écran tactile. Mettre en œuvre des interactions clavier, souris et toucher les uns avec les autres, assurer aucun bloquer les uns les autres.
on dirait que Chrome 24 prend maintenant en charge les événements tactiles, probablement Pour Windows 8. Donc le code affiché ici ne fonctionne plus. Au lieu d'essayer de détecter si le toucher est pris en charge par le navigateur, je lie maintenant à la fois les événements de toucher et de cliquer et m'assure qu'un seul est appelé:
myCustomBind = function(controlName, callback) {
$(controlName).bind('touchend click', function(e) {
e.stopPropagation();
e.preventDefault();
callback.call();
});
};
et puis l'appelant:
myCustomBind('#mnuRealtime', function () { ... });
Espérons que cette aide !
var isTouchScreen = 'createTouch' in document;
ou
var isTouchScreen = 'createTouch' in document || screen.width <= 699 ||
ua.match(/(iPhone|iPod|iPad)/) || ua.match(/BlackBerry/) ||
ua.match(/Android/);
serait une vérification plus approfondie, je suppose.
j'utilise:
if(jQuery.support.touch){
alert('Touch enabled');
}
in jQuery mobile 1.0.1
tous les navigateurs pris en charge sauf Firefox pour le bureau toujours vrai en raison de Firefox pour le soutien de bureau responsive design pour le développeur même vous cliquez sur le bouton-pression ou non!
J'espère que Mozilla corrigera cela dans la prochaine version.
J'utilise Firefox 28 desktop.
function isTouch()
{
return !!("ontouchstart" in window) || !!(navigator.msMaxTouchPoints);
}
j'ai également eu beaucoup de mal avec différentes options sur la façon de détecter dans Javascript si la page est affichée sur un écran tactile ou non. IMO, à ce jour, il n'existe pas de véritable option pour détecter correctement cette option. Les navigateurs signalent soit des événements tactiles sur les machines de bureau (parce que le système D'exploitation est peut-être prêt au toucher), soit certaines solutions ne fonctionnent pas sur tous les appareils mobiles.
à la fin, j'ai réalisé que je suivais la mauvaise approche dès le début: Si ma page devait regarder similaire sur les appareils tactiles et non tactiles, Je ne devrais peut-être pas avoir à me soucier de détecter la propriété du tout: Mon scénario était de désactiver les touches d'outils sur les boutons sur les appareils tactiles comme ils mènent à des doubles-tapes où je voulais un seul robinet pour activer le bouton.
ma solution était de refactor la vue de sorte qu'aucune infobulle n'était nécessaire sur un bouton, et à la fin je n'ai pas eu besoin de détecter l'appareil tactile de Javascript avec des méthodes que tous ont leurs inconvénients .
vous pouvez installer modernizer et utiliser un simple événement tactile. C'est très efficace et fonctionne sur tous les appareils que j'ai testé, y compris windows surface!
j'ai créé 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 réponse pratique semble être celle qui considère le contexte:
1) site Public (pas de login)
Coder L'IU pour qu'il fonctionne avec les deux options ensemble.
2) Connexion du site
Saisissez si un mouvement de souris s'est produit sur le formulaire de connexion, et enregistrez-le dans une entrée cachée. La valeur est transmise avec les identifiants de connexion et ajoutée à l'utilisateur session , de sorte qu'il peut être utilisé pour toute la durée de la session.
Jquery à ajouter à la page de connexion seulement:
$('#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 à @Dave Burt et +1 à @Martin Lantzsch sur leurs réponses)
jQuery v1.11.3
Il y a beaucoup de bonnes informations dans les réponses fournies. Mais, récemment, j'ai passé beaucoup de temps à essayer de lier tout ensemble dans une solution de travail pour accomplir deux choses:
- Détecter que l'appareil utilisé est un type d'écran tactile de l'appareil.
- détecter que le dispositif a été mis sur écoute.
outre ce billet et Détection des dispositifs d'écran tactile avec Javascript , j'ai trouvé ce post par Patrick Lauke extrêmement utile: https://hacks.mozilla.org/2013/04/detecting-touch-its-the-why-not-the-how /
voici le 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! la méthode *.on( events [, selector ] [, data ], handler )
doit avoir un sélecteur, généralement un élément, qui peut gérer l'événement "touchstart", ou tout autre événement similaire associé à toucher. Dans ce cas, c'est l'élément de lien hypertexte "un".
Maintenant, vous n'avez pas besoin de gérer le clic régulier de la souris dans JavaScript, parce que vous pouvez utiliser CSS pour gérer ces événements en utilisant des sélecteurs pour l'hyperlien " A "élément comme so:
/* unvisited link */
a:link
{
}
/* visited link */
a:visited
{
}
/* mouse over link */
a:hover
{
}
/* selected link */
a:active
{
}
Note: il y a aussi d'autres sélecteurs...
le problème
en raison de dispositifs hybrides qui utilisent une combinaison de toucher et d'entrée de souris, vous devez être en mesure dynamiquement changer l'état / la variable qui commande si un morceau de code doit courir si l'utilisateur est un utilisateur tactile ou non.
Touch aussi le feu mousemove
sur le robinet.
Solution
- supposons que le toucher est faux à la charge.
- attendez qu'un événement
touchstart
soit déclenché, puis réglez-le à true. - si touchstart a été tiré, ajouter un gestionnaire mousemove.
- si le temps entre deux évènements mousemove était inférieur à 20ms, supposons qu'ils utilisent une souris comme entrée. Supprimez l'événement car il n'est plus nécessaire et mousemove est un événement coûteux pour les appareils de la souris.
- dès que touchstart est redémarré( l'utilisateur est retourné à l'utilisation de touch), la variable est définie sur true. Et répétez le processus pour qu'il soit déterminé de façon dynamique. Si par miracle mousemove est tiré deux fois sur touch de façon absurde rapidement (dans mes essais, il est virtuellement impossible de le faire dans les 20m), le prochain touchstart le ramènera à la vraie.
testé sur Safari iOS et Chrome pour Android.
Note: Pas sûr à 100% Sur le pointeur-événements pour Surface MS, etc.
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);
}
Mesure jQuery support
objet:
jQuery.support.touch = 'ontouchend' in document;
Et maintenant vous pouvez le vérifier n'importe où, comme ceci:
if( jQuery.support.touch )
// do touch stuff
cela semble bien fonctionner pour moi jusqu'à présent:
//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)
}
note rapide à ceux qui pourraient être tentés d'écrire window.ontouchstart !== undefined
-- > veuillez répondre micnic, car undefined
n'est pas un mot clé en JavaScript. Grand problème si develop écrit quelque chose comme:
undefined = window.ontouchstart;
développeur peut faire non défini tout ce qu'ils veulent, et vous pouvez aussi bien vérifier si window.ontouchstart = myNonExistingWord;
sans manquer de respect à ceux qui ont donné cette réponse: assez sûr que j'ai écrit que dans mon code aussi ;)
quand une souris est attachée, on peut supposer avec un taux d'hittrate assez élevé (je dirais pratiquement 100%) que l'utilisateur déplace la souris au moins une petite distance après la page est prête - sans aucun clic. Le mécanisme ci-dessous le détecte. S'il est détecté, je considère qu'il s'agit d'un signe d'absence de support tactile ou, s'il est supporté, d'une importance mineure lorsqu'une souris est utilisée. L'appareil tactile est présumé s'il n'est pas détecté.
MODIFIER Cette approche peut ne pas convenir à toutes les fins. Il peut être utilisé pour contrôler la fonctionnalité qui est activée en fonction de l'interaction de l'utilisateur sur la page chargée, par exemple un visualiseur d'image. Le code ci-dessous laissera aussi l'événement mousemove lié sur les appareils sans souris comme il ressort maintenant. D'autres approches peuvent être mieux.
en gros, il va comme ceci (désolé pour jQuery, mais similaire en Javascript pur):
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;
}));
vous pouvez utiliser le code suivant:
function isTouchDevice() {
var el = document.createElement('div');
el.setAttribute('ongesturestart', 'return;'); // or try "ontouchstart"
return typeof el.ongesturestart === "function";
}
Source: Détection tactile de navigation et @mplungjan post .
la solution ci-dessus était basée sur l'article detecting event support without browser sniffing .
vous pouvez vérifier les résultats à la suivante page test .
veuillez noter que le code ci-dessus teste seulement si le navigateur supporte les toucher, ne pas l'appareil. Donc, si vous avez Ordinateur Portable Avec Écran Tactile, votre navigateur peut ne pas avoir le soutien pour les événements tactiles. Le Chrome récent soutient des événements touch , mais un autre navigateur ne peut pas.
, Vous pouvez aussi essayer:
if (document.documentElement.ontouchmove) {
// ...
}
mais il peut ne pas fonctionner sur les appareils iPhone.