Écran tactile et souris

Tous ensemble pour la première fois

Introduction

Depuis près de trente ans, les expériences informatiques sur ordinateur de bureau sont centrées sur un clavier et une souris ou un pavé tactile comme principaux dispositifs d'entrée utilisateur. Au cours de la dernière décennie, cependant, les smartphones et les tablettes ont introduit un nouveau paradigme d'interaction : le tactile. Avec l'arrivée des ordinateurs Windows 8 tactiles, et maintenant avec le lancement du Chromebook Pixel tactile, l'écran tactile fait désormais partie de l'expérience attendue sur ordinateur. L'un des plus grands défis consiste à créer des expériences qui fonctionnent non seulement sur les appareils tactiles et les appareils avec souris, mais aussi sur les appareils sur lesquels l'utilisateur utilise les deux méthodes d'entrée, parfois simultanément.

Cet article vous aidera à comprendre comment les fonctionnalités tactiles sont intégrées au navigateur, comment intégrer ce nouveau mécanisme d'interface à vos applications existantes et comment la saisie tactile peut s'intégrer à la saisie à la souris.

État de la technologie tactile sur la plate-forme Web

L'iPhone a été la première plate-forme populaire à intégrer des API tactiles dédiées au navigateur Web. Plusieurs autres fournisseurs de navigateurs ont créé des interfaces d'API similaires conçues pour être compatibles avec l'implémentation iOS, qui est désormais décrite par la spécification "Touch Events version 1". Les événements tactiles sont compatibles avec Chrome et Firefox sur ordinateur, Safari sur iOS, Chrome et le navigateur Android sur Android, ainsi que d'autres navigateurs mobiles comme le navigateur BlackBerry.

Mon collègue Boris Smus a écrit un excellent tutoriel HTML5Rocks sur les événements tactiles qui reste un bon moyen de se lancer si vous n'avez jamais travaillé avec les événements tactiles auparavant. En fait, si vous n'avez jamais travaillé avec des événements tactiles, lisez cet article maintenant, avant de continuer. Continuez, je vais patienter.

Vous avez terminé ? Maintenant que vous avez une connaissance de base des événements tactiles, le défi de l'écriture d'interactions tactiles est que les interactions tactiles peuvent être très différentes des événements de souris (et des événements de pavé tactile et de trackball qui émulent la souris). Bien que les interfaces tactiles tentent généralement d'émuler les souris, cette émulation n'est pas parfaite ni complète. Vous devez vraiment travailler sur les deux styles d'interaction et vous devrez peut-être prendre en charge chaque interface indépendamment.

Plus important encore: l'utilisateur peut avoir à la fois un écran tactile et une souris

De nombreux développeurs ont créé des sites qui détectent de manière statique si un environnement est compatible avec les événements tactiles, puis supposent qu'ils ne doivent prendre en charge que les événements tactiles (et non les événements de souris). Cette hypothèse est désormais erronée. En effet, la présence d'événements tactiles ne signifie pas que l'utilisateur utilise principalement cet appareil d'entrée tactile. Des appareils tels que le Chromebook Pixel et certains ordinateurs portables Windows 8 sont désormais compatibles avec les modes de saisie à la souris et tactiles, et d'autres le seront bientôt. Sur ces appareils, il est tout à fait naturel que les utilisateurs utilisent à la fois la souris et l'écran tactile pour interagir avec les applications. Par conséquent, "compatible avec l'écran tactile" ne signifie pas "ne nécessite pas de souris". Vous ne pouvez pas considérer le problème comme "je dois écrire deux styles d'interaction différents et passer de l'un à l'autre". Vous devez réfléchir à la façon dont les deux interactions fonctionneront ensemble et indépendamment. Sur mon Chromebook Pixel, j'utilise souvent le pavé tactile, mais je touche également l'écran. Dans la même application ou sur la même page, je fais ce qui me semble le plus naturel à l'instant. D'autre part, certains utilisateurs d'ordinateurs portables à écran tactile n'utilisent que rarement l'écran tactile, voire jamais. Par conséquent, la présence d'une entrée tactile ne doit pas désactiver ni entraver la commande de la souris.

Malheureusement, il peut être difficile de savoir si l'environnement du navigateur d'un utilisateur est compatible avec la saisie tactile. Dans l'idéal, un navigateur sur un ordinateur de bureau indiquerait toujours la compatibilité avec les événements tactiles, de sorte qu'un écran tactile puisse être connecté à tout moment (par exemple, si un écran tactile connecté via un KVM devient disponible). C'est pour toutes ces raisons que vos applications ne doivent pas tenter de basculer entre l'écran tactile et la souris. Elles sont compatibles avec les deux !

Prise en charge simultanée de la souris et du toucher

#1 : Cliquer et appuyer : l'ordre "naturel" des choses

Le premier problème est que les interfaces tactiles tentent généralement d'émuler les clics de souris. Évidemment, car les interfaces tactiles doivent fonctionner sur des applications qui n'ont interagi qu'avec des événements de souris auparavant. Vous pouvez utiliser cette méthode comme raccourci, car les événements de clic continueront d'être déclenchés, que l'utilisateur ait cliqué avec une souris ou appuyé sur l'écran. Cependant, ce raccourci pose quelques problèmes.

Tout d'abord, vous devez faire preuve de prudence lorsque vous concevez des interactions tactiles plus avancées : lorsque l'utilisateur utilise une souris, il répond via un événement de clic, mais lorsqu'il touche l'écran, des événements tactiles et de clic se produisent. Pour un seul clic, l'ordre des événements est le suivant :

  1. touchstart
  2. touchmove
  3. touchend
  4. survol avec la souris
  5. mousemove
  6. mousedown
  7. mouseup
  8. clic

Cela signifie bien sûr que si vous traitez des événements tactiles tels que "touchstart", vous devez vous assurer de ne pas traiter également l'événement mousedown et/ou click correspondant. Si vous pouvez annuler les événements tactiles (appelez preventDefault() dans le gestionnaire d'événements), aucun événement de souris ne sera généré pour le toucher. L'une des règles les plus importantes des gestionnaires tactiles est la suivante :

Toutefois, cela empêche également d'autres comportements par défaut du navigateur (comme le défilement). Bien que vous gériez généralement l'événement tactile entièrement dans votre gestionnaire, vous devez désactiver les actions par défaut. En général, il est préférable de gérer et d'annuler tous les événements tactiles, ou d'éviter d'avoir un gestionnaire pour ces événements.

Deuxièmement, lorsqu'un utilisateur appuie sur un élément d'une page Web sur un appareil mobile, les pages qui n'ont pas été conçues pour les interactions mobiles présentent un délai d'au moins 300 millisecondes entre l'événement touchstart et le traitement des événements de souris (mousedown). Vous pouvez le faire avec Chrome. Vous pouvez activer l'option "Émuler les événements tactiles" dans les outils pour les développeurs Chrome pour vous aider à tester les interfaces tactiles sur un système non tactile.

Ce délai permet au navigateur de déterminer si l'utilisateur effectue un autre geste, en particulier un zoom avec un double appui. Bien évidemment, cela peut poser problème si vous souhaitez obtenir une réponse instantanée à un geste. Des travaux sont en cours pour essayer de limiter les scénarios dans lesquels ce délai se produit automatiquement.

Chrome pour Android Navigateur Android Opera Mobile pour Android) Firefox pour Android Safari pour iOS
Fenêtre d'affichage non évolutive Aucun début différé 300ms 300ms Aucun début différé 300ms
Aucune fenêtre d'affichage 300ms 300ms 300ms 300ms 300ms

Le premier moyen (et le plus simple) d'éviter ce délai est d'indiquer au navigateur mobile que vous n'aurez pas besoin de zoomer sur votre page. Pour ce faire, utilisez une fenêtre d'affichage fixe, par exemple en insérant dans votre page les éléments suivants:

<meta name="viewport" content="width=device-width,user-scalable=no">

Bien entendu, cette méthode n'est pas toujours appropriée, car elle désactive le zoom par pincement, qui peut être nécessaire pour des raisons d'accessibilité. Utilisez-le donc avec parcimonie, le cas échéant (si vous désactivez la mise à l'échelle par l'utilisateur, vous pouvez proposer un autre moyen d'améliorer la lisibilité du texte dans votre application). De plus, pour Chrome sur les appareils de classe ordinateur de bureau compatibles avec le tactile et les autres navigateurs sur les plates-formes mobiles lorsque la page comporte des vues d'écran non évolutives, ce délai ne s'applique pas.

N° 2: Les événements de déplacement de souris ne sont pas déclenchés par le toucher

À ce stade, il est important de noter que l'émulation des événements de souris dans une interface tactile ne s'étend généralement pas à l'émulation des événements mousemove. Par conséquent, si vous créez une belle commande contrôlée par la souris qui utilise des événements mousemove, elle ne fonctionnera probablement pas avec un appareil tactile, sauf si vous ajoutez également des gestionnaires de mouvements tactiles.

Les navigateurs implémentent généralement automatiquement l'interaction appropriée pour les interactions tactiles sur les commandes HTML. Par exemple, les commandes de plage HTML5 ne fonctionnent que lorsque vous utilisez des interactions tactiles. Toutefois, si vous avez implémenté vos propres commandes, elles ne fonctionneront probablement pas avec les interactions de type "cliquer-déplacer". En effet, certaines bibliothèques couramment utilisées (comme jQueryUI) ne prennent pas encore en charge de manière native les interactions tactiles de cette manière (bien que pour jQueryUI, plusieurs correctifs de type "monkey-patch" résolvent ce problème). C'est l'un des premiers problèmes que j'ai rencontrés lors de la mise à niveau de mon application Web Audio Playground pour qu'elle fonctionne avec l'écran tactile. Les curseurs étaient basés sur jQueryUI et ne fonctionnaient donc pas avec les interactions cliquer-glisser. J'ai remplacé les sélecteurs de plage HTML5, et ils ont fonctionné. Bien sûr, j'aurais pu simplement ajouter des gestionnaires de mouvement tactile pour mettre à jour les curseurs, mais il y a un problème avec cela…

N° 3: Touchmove et MouseMove sont deux choses différentes

J'ai vu plusieurs développeurs tomber dans le piège d'appeler les mêmes chemins de code dans les gestionnaires touchmove et mousemove. Le comportement de ces événements est très proche, mais légèrement différent. En particulier, les événements tactiles ciblent toujours l'élément où le toucher a commencé, tandis que les événements de souris ciblent l'élément actuellement sous le curseur de la souris. C'est pourquoi nous avons des événements mouseover et mouseout, mais il n'existe pas d'événements touchover et touchout correspondants, mais uniquement touchend.

Le problème le plus courant est que vous supprimez (ou déplacez) l'élément que l'utilisateur a commencé à appuyer. Par exemple, imaginez un carrousel d'images avec un gestionnaire tactile sur l'ensemble du carrousel pour permettre un comportement de défilement personnalisé. À mesure que les images disponibles changent, vous supprimez certains éléments <img> et en ajoutez d'autres. Si l'utilisateur commence à appuyer sur l'une de ces images et que vous la supprimez, votre gestionnaire (qui se trouve sur un ancêtre de l'élément img) cessera simplement de recevoir des événements tactiles (car ils sont distribués à une cible qui n'est plus dans l'arborescence). Il semblera que l'utilisateur maintient son doigt à un endroit même s'il a pu le déplacer et l'enlever.

Bien entendu, vous pouvez éviter ce problème en évitant de supprimer les éléments qui ont (ou ont des ancêtres qui possèdent) des gestionnaires tactiles lorsqu'une commande tactile est active. Au lieu d'enregistrer des gestionnaires touchend/touchmove statiques, nous vous recommandons d'attendre d'obtenir un événement touchstart, puis d'ajouter des gestionnaires touchmove/touchend/touchcancel à la cible de l'événement touchstart (et de les supprimer à la fin/à l'annulation). De cette façon, vous continuerez à recevoir les événements tactiles même si l'élément cible est déplacé/supprimé. Vous pouvez jouer avec ici : appuyez sur le cadre rouge et appuyez sur Échap pour le supprimer du DOM.

N° 4 : Toucher et passer la souris

La métaphore du pointeur de souris a séparé la position du curseur de la sélection active, ce qui a permis aux développeurs d'utiliser des états de survol pour masquer et afficher des informations susceptibles d'intéresser les utilisateurs. Toutefois, pour le moment, la plupart des interfaces tactiles ne détectent pas le "pointage" d'un doigt sur une cible. Par conséquent, vous ne devez pas fournir d'informations sémantiquement importantes (par exemple, en fournissant une fenêtre pop-up "Qu'est-ce que cette commande ?", par exemple, "en quoi consiste cette commande ?"), sauf si vous proposez également un moyen tactile d'accéder à ces informations. Vous devez faire preuve de prudence lorsque vous utilisez le survol pour transmettre des informations aux utilisateurs.

Fait intéressant, la pseudo-classe CSS :hover PEUT être déclenchée par des interfaces tactiles dans certains cas. Si vous appuyez sur un élément, il devient :actif tant que l'onglet est appuyé, et il acquiert également l'état :hover. (Dans Internet Explorer, le survol s'active uniquement lorsque l'utilisateur a le doigt appuyé sur l'écran. Dans les autres navigateurs, il reste actif jusqu'au prochain appui ou au prochain mouvement de la souris.) Il s'agit d'une bonne approche pour faire fonctionner les menus contextuels sur les interfaces tactiles. L'activation d'un élément entraîne l'application de l'état :hover. Exemple :

<style>
img ~ .content {
  display:none;
}

img:hover ~ .content {
  display:block;
}
</style>

<img src="/awesome.png">
<div class="content">This is an awesome picture of me</div>

Une fois qu'un autre élément est sélectionné, il n'est plus actif et l'état de survol disparaît, comme si l'utilisateur utilisait un pointeur de souris et l'avait déplacé hors de l'élément. Vous pouvez encapsuler le contenu dans un élément <a> afin d'en faire également une tabulation. De cette façon, l'utilisateur peut activer ou désactiver les informations supplémentaires lors d'un survol ou d'un clic de souris, d'une pression sur l'écran ou d'une pression sur une touche, sans JavaScript. J'ai été agréablement surpris lorsque j'ai commencé à travailler pour que mon Web Audio Playground fonctionne bien avec les interfaces tactiles. Mes menus pop-up fonctionnaient déjà bien sur les écrans tactiles, car j'avais utilisé ce type de structure.

La méthode ci-dessus fonctionne bien pour les interfaces basées sur le pointeur de la souris, ainsi que pour les interfaces tactiles. Contrairement à l'utilisation d'attributs "title" au survol, qui ne s'affichent PAS lorsque l'élément est activé:

<img src="/awesome.png" title="this doesn't show up in touch">

N° 5: Précision tactile ou à la souris

Bien que les souris soient conceptuellement dissociées de la réalité, il s'avère qu'elles sont extrêmement précises, car le système d'exploitation sous-jacent suit généralement la précision exacte du curseur en pixels. D'autre part, les développeurs d'applications mobiles ont découvert que les gestes tactiles sur un écran tactile ne sont pas aussi précis, principalement en raison de la taille de la surface du doigt lorsqu'il est en contact avec l'écran (et en partie parce que vos doigts masquent l'écran).

De nombreux individus et entreprises ont effectué des recherches approfondies sur l'expérience utilisateur sur la conception d'applications et de sites qui prennent en charge les interactions tactiles, et de nombreux livres ont été écrits sur ce sujet. Le conseil de base est d'augmenter la taille des zones cibles tactiles en augmentant la marge intérieure, et de réduire le risque d'utilisation incorrecte en augmentant la marge entre les éléments. (Les marges ne sont pas incluses dans la gestion de la détection des éléments touchés pour les événements tactiles et de clic, contrairement à la marge intérieure.) L'une des principales corrections que j'ai apportées au Web Audio Playground a consisté à augmenter la taille des points de connexion afin qu'ils soient plus faciles à toucher avec précision.

De nombreux fournisseurs de navigateurs qui gèrent des interfaces tactiles ont également introduit une logique dans le navigateur pour aider à cibler l'élément approprié lorsqu'un utilisateur appuie sur l'écran et réduire la probabilité de clics incorrects. Toutefois, cela ne corrige généralement que les événements de clic, et non les mouvements (bien qu'Internet Explorer semble également modifier les événements mousedown/mousemove/mouseup).

#6: Limitez les gestionnaires de gestes tactiles, sinon ils risquent de perturber le défilement

Il est également important de limiter les gestionnaires tactiles aux éléments dont vous avez besoin. Les éléments tactiles peuvent avoir une bande passante très élevée. Il est donc important d'éviter les gestionnaires tactiles sur les éléments de défilement (car votre traitement peut interférer avec les optimisations du navigateur pour un défilement tactile rapide et sans à-coups. Les navigateurs modernes tentent de faire défiler un thread GPU, mais cela est impossible s'ils doivent d'abord vérifier avec JavaScript si chaque événement tactile sera géré par l'application). Vous pouvez consulter un exemple de ce comportement.

Pour éviter ce problème, assurez-vous que si vous ne gérez que des événements tactiles dans une petite partie de votre UI, vous n'y attachez que des gestionnaires tactiles (et non, par exemple, sur le <body> de la page). En résumé, limitez autant que possible la portée de vos gestionnaires tactiles.

#7: Multipoint

Le dernier défi intéressant est que, bien que nous l'ayons appelée interface utilisateur "tactile", la prise en charge est presque universellement multipoint. Autrement dit, les API fournissent plusieurs entrées tactiles à la fois. Lorsque vous commencez à prendre en charge les gestes tactiles dans vos applications, vous devez réfléchir à l'impact que plusieurs gestes peuvent avoir sur votre application.

Si vous avez créé des applications principalement basées sur la souris, vous avez l'habitude de créer avec un seul point de curseur au maximum. En effet, les systèmes n'acceptent généralement pas plusieurs curseurs de souris. Pour de nombreuses applications, vous ne mapperez que des événements tactiles sur une seule interface de curseur. Toutefois, la plupart des appareils que nous avons vus pour la saisie tactile sur ordinateur peuvent gérer au moins deux entrées simultanées, et la plupart des nouveaux appareils semblent prendre en charge au moins cinq entrées simultanées. Bien entendu, pour développer un clavier piano à l'écran, vous devez pouvoir prendre en charge plusieurs entrées tactiles simultanées.

Les API tactiles W3C actuellement implémentées ne disposent d'aucune API permettant de déterminer le nombre de points de contact compatibles avec le matériel. Vous devrez donc estimer le nombre de points de contact souhaités par vos utilisateurs. Vous pouvez également prêter attention au nombre de points de contact que vous voyez dans la pratique et vous adapter. Par exemple, dans une application de piano, si vous ne voyez jamais plus de deux points de contact, vous pouvez ajouter des UI "cordes". L'API PointerEvents dispose d'une API permettant de déterminer les fonctionnalités de l'appareil.

Retouches

Nous espérons que cet article vous aura donné des conseils sur les défis courants liés à l'implémentation des interactions tactiles en plus de celles de la souris. Bien entendu, le plus important est de tester votre application sur un mobile, une tablette et dans des environnements de bureau tactiles et à la souris. Si vous ne disposez pas d'un matériel tactile et d'une souris, utilisez l'option Émuler les événements tactiles de Chrome pour tester les différents scénarios.

En suivant ces conseils, vous pouvez créer des expériences interactives attrayantes qui fonctionnent bien avec les entrées tactiles et les entrées à la souris, et même les deux styles d'interaction en même temps.