web-dev-qa-db-fra.com

Un clic dans iOS Safari déclenche un "état de survol" sur l'élément sous lequel vous avez tapé

Sur iOS Safari (je ne pense pas que la version d'iOS importe, mais je teste sur iOS (Safari) 11), si j'ai un <div> positionné sur un élément ayant un effet :hover, et le <div> a un événement qui le fait disparaître lorsque vous cliquez dessus, puis mon lien "sous-dessous" obtient l'effet de survol appliqué après la suppression de l'élément du DOM.

Voir ci-dessous pour un GIF animé de ce dont je parle:

 iOS click through

J'ai donné au bouton un fond transparent pour que vous puissiez voir le lien qui se trouve derrière. Lorsque j'appuie sur le bouton à un endroit où le lien n'est pas situé, le lien (c'est-à-dire Some link) reste bleu et ne change pas en état de survol rouge.

Cependant, lorsque je tape sur la variable div dans un emplacement qui se trouve être directement sur le lien, une fois la variable div supprimée du DOM, son état de survol est appliqué.

En cliquant sur le lien après chacune de ces actions, l'événement on.click (une fenêtre d'alerte) est déclenché correctement.

Je _ {not} _ vois ce problème sous Android sur Chrome (voir l'exemple ci-dessous):

 Android click through working

Ci-dessous, vous trouverez également l'exemple HTML/CSS/JS que j'ai utilisé; la configuration est assez simple.

J'aimerais que iOS agisse de la même manière qu'Android Chrome: en cliquant sur un élément immédiatement supprimé du DOM ne devrait pas déclencher un état :hover pour un élément immédiatement derrière.

document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function() {
    button.parentNode.removeChild(button);
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a:link    { color: blue }
a:visited { color: blue }
a:hover   { color: red }
a:active  { color: green }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
<a href="#">Some link</a>
<div class="button">Click me!</div>

16
romellem

Si vous avez l'option de désactiver le survol, vous pouvez le faire avec un peu de piratage.

Ajoutez d’abord cette ligne dans le gestionnaire d’événements "DOMContentLoaded".

var canHover = !(matchMedia('(hover: none)').matches);
if (canHover) {
  document.body.classList.add('can-hover');
}

Il ajoutera la classe .can-hover au corps de votre document html.

Ensuite, éditez simplement une règle: hover pour qu'elle corresponde à celle-ci

votre règle de css:

a:hover {
  color: red;
}

devrait être:

.can-hover a:hover {
  color: red;
}

cela devrait empêcher les appareils à écran tactile d'appliquer le style de survol à n'importe quelle ancre.

6
Milan Jaric

Avez-vous déjà essayé d’utiliser une requête multimédia pour tester: la capacité de survol?

Voir https://drafts.csswg.org/mediaqueries/#hover

4
Josh Palmeri

... il est clair que c'est le comportement souhaité sur iOS, même lorsque vous faites glisser votre doigt sur une liste d'éléments pouvant être survolés.

Si ce que vous essayez d'éviter, c'est uniquement l'effet de survol, voici ce que je ferais. Je voudrais obtenir le périphérique en utilisant une fonction JS, appliquer une classe sur la balise body et supprimer tous les effets de survol si nécessaire.

Javascript:

function isAppleDevice() {
  return (
    (navigator.userAgent.toLowerCase().indexOf("ipad") > -1) ||
    (navigator.userAgent.toLowerCase().indexOf("iphone") > -1) ||
    (navigator.userAgent.toLowerCase().indexOf("iPod") > -1)
   );
}
if (isAppleDevice() {
  $('body').addClass('is_Apple')
}

CSS:

.is_Apple a:hover {
  // same styling as not hovering
}
4
scooterlord

Cela semble être une décision de conception inhérente à iOS (ou peut-être que Chrome est la décision de conception prise par eux; impossible à dire). Il semble que iOS est conçu pour être "semblable à la souris". Il jette même des "survols" sur les pages Web, même sur leurs appareils tactiles. J'ai essayé de trouver un moyen de déterminer si l'utilisateur possède une souris pour pouvoir désactiver les effets de survol s'il en existe un, mais je ne trouve rien qui puisse fonctionner correctement.

Je pense que Windows fait la même chose avec le toucher, aussi. Toucher un point déplace effectivement le pointeur de la souris là-bas et clique, laissant le pointeur de la souris.

Vous devrez peut-être simplement modifier votre conception s'il s'agit d'un compromis.

1
Joseph Hansen

Cela semble être le comportement souhaité dans Safari. La documentation d'Apple indique que les tapotements à un doigt sont traités comme des événements de souris et indique quels événements sont déclenchés lors d'un tapotement. Il y a une mouseover au début du tap, mais une mouseout n'est déclenchée que lorsque vous cliquez sur autre chose. Cela implique que Safari suppose que le pointeur reste au même endroit jusqu'au prochain tap, ce qui signifie qu'il est logique que l'élément inférieur soit à l'état de survol.

J'ai essayé votre code dans Chrome sous Android, et Chrome et Firefox sous Windows (je n'ai pas d'appareil Apple). Dans les trois cas, lorsque je clique sur le <div> à l'aide d'une souris (par-dessus le lien), le style de survol est appliqué au lien par la suite, à moins que je n'éloigne le curseur du lien avant de relâcher la souris. Si je tape sur le <div> avec mon doigt sur l'écran tactile, le lien n'a pas le style de survol.

Firefox et Chrome semblent être compatibles l'un avec l'autre pour le toucher et la souris, mais Safari semble (par sa conception) traiter l'écran tactile comme une souris: il se comporte de la même manière pour une presse tactile que pour Chrome et Firefox pour un clic de souris.

Je ne pense pas que ce soit un bogue que vous devez corriger ou contourner. À moins que vous ne sachiez que tous vos utilisateurs utiliseront une combinaison matériel/navigateur spécifique, vous devrez probablement prévoir l’éventualité qu’ils utilisent une souris, un écran tactile ou peut-être les deux à la fois. et concevoir une interface utilisateur qui fonctionne pour tous ces cas. Mon ordinateur portable Windows et ma tablette Android ont tous les deux un tapis de souris et un écran tactile. J'utilise parfois une souris USB OTG avec mon téléphone Android.

Vous pouvez également consulter l'API Pointer Events , qui fonctionne dans Chrome, IE et Edge (à ne pas confondre avec la propriété CSS pointer-events mentionnée par @erier). Étant donné que l'API traite d'événements plutôt que de CSS, cela ne vous aidera pas directement à bien coiffer, mais montre les efforts en cours pour que les navigateurs réagissent de manière cohérente à différents types de périphériques d'entrée.

1
JRI

J'ai eu un problème similaire que j'ai résolu en ajoutant des événements de pointeur none pendant une fraction de seconde juste avant la suppression de l'élément, puis en le réinitialisant une fois qu'il est parti.

document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function() {
    document.querySelector('a').classList.add("no-click");
    button.parentNode.removeChild(button);
    setTimeout(function() {
        document.querySelector('a').classList.remove("no-click");
    },1);
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a:link    { color: blue }
a:visited { color: blue }
a:hover   { color: red }
a:active  { color: green }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
.no-click {
    pointer-events: none;
}
<a href="#">Some link</a>
<div class="button">Click me!</div>

1
marmite

Je ne sais pas si cela fonctionnerait dans votre code de production, mais cela devrait être le cas pour cet exemple. 

Vous pouvez cracher vos règles de survol dans une classe et appliquer cette classe au lien dans votre rappel de suppression de bouton, après l'avoir zappé dans le DOM.

Si cela ne fonctionne toujours pas, vous pouvez ajouter la classe dans un callback onmouseover. Cela ne fonctionnerait qu'après que le bouton aurait été supprimé et après avoir quitté (le cas échéant) et ressaisi le lien.

Tout cela est un peu compliqué, mais cela vous permettrait de personnaliser le comportement dans les navigateurs/systèmes d'exploitation.

0
allnodcoms

Je pense que ce bidouillage peut fonctionner.

Vous devez désactiver le survol avec une classe et, lorsque le div le plus haut cliqué, ajouter un écouteur d'événements qui supprimera la classe bloquant le survol lors du déplacement de la souris.

document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function() {
    button.parentNode.removeChild(button);
    var body = document.querySelector("body");
    body.addEventListener("mousemove", function() {
            var someLink = document.querySelector(".some-link");
            someLink.classList.remove("no-hover");
        });
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a:link    { color: blue }
a:visited { color: blue }
a:hover   { color: red }
a:active  { color: green }

a.no-hover:hover { color: blue }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
<a href="#" class="some-link no-hover">Some link</a>
<div class="button">Click me!</div>

0
Joseph Hansen

Utiliser des événements de pointeur pourrait aider ici.

document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function() {
    button.parentNode.removeChild(button);
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a {pointer-events: none;}
a:link    { color: blue; pointer-events: auto; }
a:visited { color: blue }
a:hover   { color: red; pointer-events: auto; }
a:active  { color: green; pointer-events: auto; }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
<a href="#">Some link</a>
<div class="button">Click me!</div>

0
erier

Ceci est un problème avec les navigateurs. l'état de survol existe partout même quand il ne devrait pas.

J'ajouterais une classe de .no-touch au corps et n'appliquerais que ceux-ci.

if (!("ontouchstart" in document.documentElement)) {
    document.body.classList.add('no-touch')
}

Voici tout ensemble

if (!("ontouchstart" in document.documentElement)) {
    document.body.classList.add('no-touch')
}
document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function(e) {
    button.parentNode.removeChild(button);
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a:link    { color: blue }
a:visited { color: blue }
.no-touch a:hover   { color: red }
a:active  { color: green }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
<a href="#">Some link</a>
<div class="button">Click me!</div>

J'apprécie que ce ne soit peut-être pas la réponse que vous recherchez, mais cela assurera la cohérence entre Android et iOS. Aidera potentiellement d'autres personnes ayant le même problème à l'avenir.

0
Joao Lopes