Les écrans tactiles sont disponibles sur de plus en plus d'appareils, des téléphones aux écrans des ordinateurs. Votre application doit réagir de façon intuitive et esthétique.
Les écrans tactiles sont disponibles sur de plus en plus d'appareils, allant des téléphones aux écrans d'ordinateur. Lorsque vos utilisateurs choisissent d'interagir avec votre interface utilisateur, votre application doit réagir à leur pression de manière intuitive.
Répondre aux états des éléments
Avez-vous déjà touché ou cliqué sur un élément d'une page Web pour vous demander si le site l'avait bien détecté ?
Il vous suffit de modifier la couleur d'un élément lorsque les utilisateurs touchent des parties de votre interface utilisateur ou interagissent avec elles pour s'assurer que votre site fonctionne. Non seulement cela atténue la frustration, mais cela peut également donner une impression rapide et réactive.
Les éléments DOM peuvent hériter de l'un des états suivants: par défaut, focus, survol et actif. Pour modifier l'interface utilisateur pour chacun de ces états, nous devons appliquer des styles aux pseudo-classes :hover
, :focus
et :active
, comme indiqué ci-dessous:
.btn {
background-color: #4285f4;
}
.btn:hover {
background-color: #296cdb;
}
.btn:focus {
background-color: #0f52c1;
/* The outline parameter suppresses the border
color / outline when focused */
outline: 0;
}
.btn:active {
background-color: #0039a8;
}
Dans la plupart des navigateurs mobiles, les états de hover et/ou de hover s'appliquent à un élément dès que l'utilisateur appuie dessus.
Réfléchissez bien aux styles que vous définissez et à la façon dont ils s'afficheront pour l'utilisateur une fois qu'il aura terminé.
Supprimer les styles de navigateur par défaut
Une fois que vous avez ajouté des styles pour les différents états, vous remarquerez que la plupart des navigateurs implémentent leurs propres styles en réponse au clic de l'utilisateur. En effet, lors du lancement des appareils mobiles, un certain nombre de sites ne comportaient pas de style pour l'état :active
. Par conséquent, de nombreux navigateurs ont ajouté une couleur ou un style de surbrillance supplémentaires pour fournir des commentaires aux utilisateurs.
La plupart des navigateurs utilisent la propriété CSS outline
pour afficher un cercle autour d'un élément lorsqu'il est sélectionné. Vous pouvez le supprimer à l'aide de la commande suivante:
.btn:focus {
outline: 0;
/* Add replacement focus styling here (i.e. border) */
}
Safari et Chrome ajoutent une couleur de surbrillance en appuyant sur l'écran, qui peut être bloquée avec la propriété CSS -webkit-tap-highlight-color
:
/* Webkit / Chrome Specific CSS to remove tap
highlight color */
.btn {
-webkit-tap-highlight-color: transparent;
}
Internet Explorer sur Windows Phone présente un comportement similaire, mais il est supprimé via une balise Meta:
<meta name="msapplication-tap-highlight" content="no">
Firefox a deux effets secondaires à gérer.
La pseudo-classe -moz-focus-inner
, qui ajoute un contour sur les éléments tactiles, que vous pouvez supprimer en définissant border: 0
Si vous utilisez un élément <button>
dans Firefox, un dégradé est appliqué. Vous pouvez le supprimer en définissant background-image: none
.
/* Firefox Specific CSS to remove button
differences and focus ring */
.btn {
background-image: none;
}
.btn::-moz-focus-inner {
border: 0;
}
Désactivation de la sélection de l'utilisateur
Lorsque vous créez votre UI, il peut arriver que vous souhaitiez que les utilisateurs interagissent avec vos éléments, mais que vous souhaitiez supprimer le comportement par défaut consistant à sélectionner du texte en appuyant de manière prolongée sur un appui prolongé ou en faisant glisser la souris sur votre UI.
Vous pouvez le faire avec la propriété CSS user-select
, mais sachez que cette opération sur le contenu peut être extremely gênante pour les utilisateurs qui souhaitent sélectionner le texte dans l'élément.
Veillez donc à l'utiliser avec parcimonie et parcimonie.
/* Example: Disable selecting text on a paragraph element: */
p.disable-text-selection {
user-select: none;
}
Implémenter des gestes personnalisés
Si vous avez une idée d'interactions et de gestes personnalisés pour votre site, tenez compte de ces deux points:
- Compatibilité avec tous les navigateurs.
- Conserver une fréquence d'images élevée
Dans cet article, nous examinerons exactement les sujets suivants, couvrant les API dont nous avons besoin pour toucher tous les navigateurs, puis nous verrons comment utiliser efficacement ces événements.
En fonction de ce que vous souhaitez faire, vous souhaitez probablement que l'utilisateur interagisse avec un élément à la fois ou qu'il puisse interagir avec plusieurs éléments en même temps.
Nous allons examiner deux exemples dans cet article, qui illustrent tous deux la compatibilité avec tous les navigateurs et comment maintenir une fréquence d'images élevée.
Le premier exemple permettra à l'utilisateur d'interagir avec un élément. Dans ce cas, vous pouvez souhaiter que tous les événements tactiles soient attribués à cet élément unique, à condition que le geste ait initialement commencé sur l'élément lui-même. Par exemple, le fait de déplacer un doigt hors de l'élément pouvant être balayé peut toujours le contrôler.
Cela est utile, car il offre une grande flexibilité à l'utilisateur, mais applique une restriction sur la façon dont il peut interagir avec votre interface utilisateur.
Toutefois, si vous vous attendez à ce que les utilisateurs interagissent avec plusieurs éléments en même temps (à l'aide de l'écran tactile multipoint), vous devez limiter l'appui à l'élément en question.
Cette approche est plus flexible pour les utilisateurs, mais complique la logique de manipulation de l'interface utilisateur et est moins résistante aux erreurs des utilisateurs.
Ajouter des écouteurs d'événements
Dans Chrome (version 55 et ultérieures), Internet Explorer et EdgePointerEvents
sont recommandés pour implémenter des gestes personnalisés.
Dans les autres navigateurs, il s'agit de l'approche appropriée : TouchEvents
et MouseEvents
.
L'avantage de PointerEvents
est qu'il fusionne plusieurs types d'entrées, y compris les événements de souris, d'écran tactile et de stylet, en un seul ensemble de rappels. Les événements à écouter sont pointerdown
, pointermove
, pointerup
et pointercancel
.
Les équivalents dans les autres navigateurs sont touchstart
, touchmove
, touchend
et touchcancel
pour les événements tactiles. Si vous souhaitez implémenter le même geste pour la saisie à la souris, vous devez implémenter mousedown
, mousemove
et mouseup
.
Si vous avez des questions sur les événements à utiliser, consultez ce tableau des événements tactiles, de souris et de curseur.
L'utilisation de ces événements nécessite d'appeler la méthode addEventListener()
sur un élément DOM, ainsi que le nom d'un événement, une fonction de rappel et une valeur booléenne.
La valeur booléenne détermine si vous devez intercepter l'événement avant ou après que d'autres éléments aient eu l'occasion d'intercepter et d'interpréter les événements. (true
signifie que vous souhaitez que l'événement soit placé avant les autres éléments.)
Voici un exemple d'écoute du début d'une interaction.
// Check if pointer events are supported.
if (window.PointerEvent) {
// Add Pointer Event Listener
swipeFrontElement.addEventListener('pointerdown', this.handleGestureStart, true);
swipeFrontElement.addEventListener('pointermove', this.handleGestureMove, true);
swipeFrontElement.addEventListener('pointerup', this.handleGestureEnd, true);
swipeFrontElement.addEventListener('pointercancel', this.handleGestureEnd, true);
} else {
// Add Touch Listener
swipeFrontElement.addEventListener('touchstart', this.handleGestureStart, true);
swipeFrontElement.addEventListener('touchmove', this.handleGestureMove, true);
swipeFrontElement.addEventListener('touchend', this.handleGestureEnd, true);
swipeFrontElement.addEventListener('touchcancel', this.handleGestureEnd, true);
// Add Mouse Listener
swipeFrontElement.addEventListener('mousedown', this.handleGestureStart, true);
}
Gérer les interactions à un seul élément
Dans le court extrait de code ci-dessus, nous n'avons ajouté l'écouteur d'événements de démarrage que pour les événements de souris. En effet, les événements de souris ne se déclenchent que lorsque le curseur passe la souris sur l'élément auquel l'écouteur d'événements a été ajouté.
TouchEvents
suit un geste une fois qu'il a démarré, quel que soit l'endroit où il se produit, et PointerEvents
suit les événements, quel que soit l'endroit où le toucher se produit après l'appel de setPointerCapture
sur un élément DOM.
Pour les événements de mouvement et de fin de la souris, nous ajoutons les écouteurs d'événements dans la méthode de début des gestes et les écouteurs au document, ce qui signifie qu'il peut suivre le curseur jusqu'à ce que le geste soit terminé.
Voici les étapes à suivre pour ce faire:
- Ajoutez tous les écouteurs TouchEvent et PointerEvent. Pour les événements "MouseEvents", ajoutez uniquement l'événement de début.
- Dans le rappel du geste de début, liez les événements de déplacement et de fin de la souris au document. De cette façon, tous les événements de souris sont reçus, qu'ils se produisent ou non sur l'élément d'origine. Pour PointerEvents, nous devons appeler
setPointerCapture()
sur l'élément d'origine pour recevoir tous les autres événements. Gérez ensuite le début du geste. - Gérez les événements de déplacement.
- Lors de l'événement de fin, supprimez le mouvement de la souris et les écouteurs de fin du document, puis mettez fin au geste.
Vous trouverez ci-dessous un extrait de notre méthode handleGestureStart()
, qui ajoute les événements de déplacement et de fin au document:
// Handle the start of gestures
this.handleGestureStart = function(evt) {
evt.preventDefault();
if(evt.touches && evt.touches.length > 1) {
return;
}
// Add the move and end listeners
if (window.PointerEvent) {
evt.target.setPointerCapture(evt.pointerId);
} else {
// Add Mouse Listeners
document.addEventListener('mousemove', this.handleGestureMove, true);
document.addEventListener('mouseup', this.handleGestureEnd, true);
}
initialTouchPos = getGesturePointFromEvent(evt);
swipeFrontElement.style.transition = 'initial';
}.bind(this);
Le rappel de fin que nous ajoutons est handleGestureEnd()
. Il supprime les écouteurs d'événements de déplacement et de fin du document et libère la capture du pointeur lorsque le geste est terminé, comme ceci:
// Handle end gestures
this.handleGestureEnd = function(evt) {
evt.preventDefault();
if (evt.touches && evt.touches.length > 0) {
return;
}
rafPending = false;
// Remove Event Listeners
if (window.PointerEvent) {
evt.target.releasePointerCapture(evt.pointerId);
} else {
// Remove Mouse Listeners
document.removeEventListener('mousemove', this.handleGestureMove, true);
document.removeEventListener('mouseup', this.handleGestureEnd, true);
}
updateSwipeRestPosition();
initialTouchPos = null;
}.bind(this);
En suivant ce modèle d'ajout de l'événement de déplacement au document, si l'utilisateur commence à interagir avec un élément et déplace son geste en dehors de l'élément, nous continuerons à recevoir les mouvements de la souris, quel que soit leur emplacement sur la page, car le document reçoit les événements.
Ce schéma montre ce que font les événements tactiles lorsque nous ajoutons les événements de déplacement et de fin au document lorsqu'un geste commence.
Répondre efficacement au toucher
Maintenant que les événements de début et de fin sont réglés, nous pouvons répondre aux événements tactiles.
Pour tous les événements de démarrage et de déplacement, vous pouvez facilement extraire x
et y
d'un événement.
L'exemple suivant vérifie si l'événement provient d'une TouchEvent
en vérifiant si targetTouches
existe. Si c'est le cas, il extrait clientX
et clientY
dès la première pression.
Si l'événement est un PointerEvent
ou un MouseEvent
, il extrait clientX
et clientY
directement de l'événement lui-même.
function getGesturePointFromEvent(evt) {
var point = {};
if (evt.targetTouches) {
// Prefer Touch Events
point.x = evt.targetTouches[0].clientX;
point.y = evt.targetTouches[0].clientY;
} else {
// Either Mouse event or Pointer Event
point.x = evt.clientX;
point.y = evt.clientY;
}
return point;
}
Un TouchEvent
comporte trois listes contenant des données tactiles:
touches
: liste de toutes les touches actives à l'écran, quel que soit l'élément DOM sur lequel elles se trouvent.targetTouches
: liste des points de contact actuellement sur l'élément DOM auquel l'événement est lié.changedTouches
: liste des modifications apportées à l'événement, qui ont été déclenchées.
Dans la plupart des cas, targetTouches
vous offre tout ce dont vous avez besoin et dont vous avez besoin. Pour en savoir plus sur ces listes, consultez Listes tactiles.
Utiliser requestAnimationFrame
Étant donné que les rappels d'événements sont déclenchés sur le thread principal, nous voulons exécuter le moins de code possible dans les rappels de nos événements, ce qui permet de maintenir une fréquence de frames élevée et d'éviter les à-coups.
requestAnimationFrame()
nous permet de mettre à jour l'interface utilisateur juste avant que le navigateur ne dessine un cadre, ce qui nous aide à retirer certaines tâches de nos rappels d'événements.
Si vous ne connaissez pas requestAnimationFrame()
, cliquez ici pour en savoir plus.
Une implémentation type consiste à enregistrer les coordonnées x
et y
à partir des événements de démarrage et de déplacement, puis à demander une image d'animation dans le rappel de l'événement de déplacement.
Dans notre démonstration, nous stockons la position initiale du contact dans handleGestureStart()
(recherchez initialTouchPos
):
// Handle the start of gestures
this.handleGestureStart = function(evt) {
evt.preventDefault();
if (evt.touches && evt.touches.length > 1) {
return;
}
// Add the move and end listeners
if (window.PointerEvent) {
evt.target.setPointerCapture(evt.pointerId);
} else {
// Add Mouse Listeners
document.addEventListener('mousemove', this.handleGestureMove, true);
document.addEventListener('mouseup', this.handleGestureEnd, true);
}
initialTouchPos = getGesturePointFromEvent(evt);
swipeFrontElement.style.transition = 'initial';
}.bind(this);
La méthode handleGestureMove()
stocke la position de son événement avant de demander une image d'animation si nécessaire, en transmettant notre fonction onAnimFrame()
comme rappel:
this.handleGestureMove = function (evt) {
evt.preventDefault();
if (!initialTouchPos) {
return;
}
lastTouchPos = getGesturePointFromEvent(evt);
if (rafPending) {
return;
}
rafPending = true;
window.requestAnimFrame(onAnimFrame);
}.bind(this);
La valeur onAnimFrame
est une fonction qui, lorsqu'elle est appelée, modifie notre interface utilisateur pour la déplacer. En transmettant cette fonction dans requestAnimationFrame()
, nous disons au navigateur de l'appeler juste avant de mettre à jour la page (c'est-à-dire d'appliquer toutes les modifications apportées à la page).
Dans le rappel handleGestureMove()
, nous vérifions initialement si rafPending
est "false", ce qui indique si onAnimFrame()
a été appelé par requestAnimationFrame()
depuis le dernier événement de déplacement. Cela signifie qu'un seul requestAnimationFrame()
est en attente d'exécution à la fois.
Lorsque notre rappel onAnimFrame()
est exécuté, nous définissons la transformation sur tous les éléments que nous souhaitons déplacer avant de définir rafPending
sur false
, ce qui permet au prochain événement tactile de demander une nouvelle image d'animation.
function onAnimFrame() {
if (!rafPending) {
return;
}
var differenceInX = initialTouchPos.x - lastTouchPos.x;
var newXTransform = (currentXPosition - differenceInX)+'px';
var transformStyle = 'translateX('+newXTransform+')';
swipeFrontElement.style.webkitTransform = transformStyle;
swipeFrontElement.style.MozTransform = transformStyle;
swipeFrontElement.style.msTransform = transformStyle;
swipeFrontElement.style.transform = transformStyle;
rafPending = false;
}
Contrôler les gestes à l'aide des actions tactiles
La propriété CSS touch-action
vous permet de contrôler le comportement tactile par défaut d'un élément. Dans nos exemples, nous utilisons touch-action: none
pour empêcher le navigateur d'effectuer quoi que ce soit lorsque l'utilisateur appuie dessus, ce qui nous permet d'intercepter tous les événements tactiles.
/* Pass all touches to javascript: */
button.custom-touch-logic {
touch-action: none;
}
L'utilisation de touch-action: none
est une option nucléaire, car elle empêche tous les comportements par défaut du navigateur. Dans de nombreux cas, l'une des options ci-dessous est une meilleure solution.
touch-action
vous permet de désactiver les gestes implémentés par un navigateur.
Par exemple, IE10+ prend en charge un double tapotement pour zoomer. En définissant une touch-action
sur manipulation
, vous empêchez le comportement par défaut du double appui.
Cela vous permet d'implémenter vous-même un geste de double tapotement.
Vous trouverez ci-dessous une liste des valeurs touch-action
couramment utilisées:
Compatibilité avec les anciennes versions d'IE
Si vous souhaitez prendre en charge IE10, vous devez gérer les versions de PointerEvents
précédées du fournisseur.
Pour vérifier la prise en charge de PointerEvents
, vous recherchez généralement window.PointerEvent
, mais dans IE10, vous recherchez window.navigator.msPointerEnabled
.
Les noms d'événements avec les préfixes de fournisseur sont les suivants: 'MSPointerDown'
, 'MSPointerUp'
et 'MSPointerMove'
.
L'exemple ci-dessous vous montre comment vérifier la compatibilité et modifier le nom des événements.
var pointerDownName = 'pointerdown';
var pointerUpName = 'pointerup';
var pointerMoveName = 'pointermove';
if (window.navigator.msPointerEnabled) {
pointerDownName = 'MSPointerDown';
pointerUpName = 'MSPointerUp';
pointerMoveName = 'MSPointerMove';
}
// Simple way to check if some form of pointerevents is enabled or not
window.PointerEventsSupport = false;
if (window.PointerEvent || window.navigator.msPointerEnabled) {
window.PointerEventsSupport = true;
}
Pour en savoir plus, consultez cet article de Microsoft sur les mises à jour.
Reference
Pseudo-classes pour les états tactiles
La référence définitive est disponible sur la page Événements tactiles du W3C.
Événements tactiles, de souris et de curseur
Ces événements sont les éléments de base permettant d'ajouter de nouveaux gestes à votre application:
Listes tactiles
Chaque événement tactile comprend trois attributs de liste:
Activer la prise en charge de l'état actif sur iOS
Malheureusement, Safari sur iOS n'applique pas l'état active par défaut. Pour que cela fonctionne, vous devez ajouter un écouteur d'événements touchstart
au corps du document ou à chaque élément.
Vous devez effectuer cette opération derrière un test user-agent afin de ne l'exécuter que sur les appareils iOS.
L'ajout d'un début tactile au corps a l'avantage de s'appliquer à tous les éléments du DOM, mais cela peut entraîner des problèmes de performances lors du défilement de la page.
window.onload = function() {
if (/iP(hone|ad)/.test(window.navigator.userAgent)) {
document.body.addEventListener('touchstart', function() {}, false);
}
};
L'alternative consiste à ajouter les écouteurs de démarrage tactile à tous les éléments interactifs de la page, afin de réduire certains problèmes de performances.
window.onload = function() {
if (/iP(hone|ad)/.test(window.navigator.userAgent)) {
var elements = document.querySelectorAll('button');
var emptyFunction = function() {};
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('touchstart', emptyFunction, false);
}
}
};