J'ai quelques menus CSS sur mon site qui se développent avec :hover
(Sans js)
Cela fonctionne de manière semi-cassée sur les iDevices, par exemple, un tap activera la règle :hover
Et développera le menu, mais si vous tapez ailleurs, le :hover
Ne sera pas supprimé. De plus, s'il existe un lien dans l'élément :hover
, Vous devez taper deux fois pour l'activer (le premier tap déclenche :hover
, Le second tap déclenche le lien).
J'ai pu faire en sorte que les choses fonctionnent bien sur iphone en liant l'événement touchstart
.
Le problème est que parfois, safari mobile choisit toujours de déclencher la règle :hover
À partir du fichier css au lieu de mes touchstart
événements!
Je sais que c'est le problème parce que lorsque je désactive manuellement toutes les règles :hover
Dans le CSS, le safari mobile fonctionne très bien (mais les navigateurs classiques ne le sont évidemment plus).
Existe-t-il un moyen d’annuler dynamiquement les règles :hover
Pour certains éléments lorsque l’utilisateur utilise le safari mobile?
Consultez et comparez le comportement iOS ici: http://jsfiddle.net/74s35/3/ Remarque: seules certaines propriétés css déclenchent le comportement en deux clics, par exemple. affichage: aucun; mais pas fond: rouge; ou texte-décoration: souligner;
J'ai trouvé que ": hover" est imprévisible dans Safari pour iPhone/iPad. Parfois, appuyez sur l'élément pour que cet élément ": survolez", alors que parfois, il dérive vers d'autres éléments.
Pour le moment, j'ai juste un cours "sans contact" au corps.
<body class="yui3-skin-sam no-touch">
...
</body>
Et avoir toutes les règles CSS avec ": survoler" ci-dessous ".no-touch":
.no-touch my:hover{
color: red;
}
Quelque part dans la page, javascript est nécessaire pour supprimer la classe no-touch du corps.
if ('ontouchstart' in document) {
Y.one('body').removeClass('no-touch');
}
Cela ne semble pas parfait, mais cela fonctionne quand même.
:hover
n'est pas le problème ici. Safari pour iOS suit une règle très étrange. Il déclenche mouseover
et mousemove
en premier; si quelque chose est modifié au cours de ces événements, le clic et les événements connexes ne sont pas déclenchés:
mouseenter
et mouseleave
semblent être inclus, bien qu'ils ne soient pas spécifiés dans le graphique.
Si vous modifiez quoi que ce soit à la suite de ces événements, les événements de clic ne seront pas déclenchés. Cela inclut quelque chose de plus haut dans l’arbre DOM. Par exemple, cela empêchera les clics simples de fonctionner sur votre site Web avec jQuery:
$(window).on('mousemove', function() {
$('body').attr('rel', Math.random());
});
Edit: pour plus de clarté, l'événement hover
de jQuery inclut mouseenter
et mouseleave
. Ceux-ci empêcheront click
si le contenu est modifié.
La bibliothèque de détection des fonctionnalités du navigateur Modernizer inclut une vérification des événements tactiles.
Son comportement par défaut consiste à appliquer des classes à votre élément HTML pour chaque fonctionnalité détectée. Vous pouvez ensuite utiliser ces classes pour styliser votre document.
Si les événements tactiles ne sont pas activés, Modernizr peut ajouter une classe de no-touch
:
<html class="no-touch">
Et puis réglez vos styles de survol avec cette classe:
.no-touch a:hover { /* hover styles here */ }
Vous pouvez télécharger une version personnalisée de Modernizr pour inclure autant de détections de fonctionnalités que vous le souhaitez.
Voici un exemple de certaines classes pouvant être appliquées:
<html class="js no-touch postmessage history multiplebgs
boxshadow opacity cssanimations csscolumns cssgradients
csstransforms csstransitions fontface localstorage sessionstorage
svg inlinesvg no-blobbuilder blob bloburls download formdata">
Certains appareils (comme d'autres l'ont dit) ont à la fois des événements tactiles et des événements souris. La Microsoft Surface, par exemple, possède un écran tactile, un trackpad ET un stylet qui soulève les événements de survol lorsque celui-ci survole au-dessus de l'écran.
Toute solution qui désactive :hover
En fonction de la présence d'événements tactiles affectera également les utilisateurs de Surface (et de nombreux autres périphériques similaires). De nombreux nouveaux ordinateurs portables sont tactiles et réagiront aux événements tactiles. Désactiver le vol stationnaire est donc une très mauvaise pratique.
C'est un bug dans Safari, rien ne peut justifier ce comportement terrible. Je refuse de saboter les navigateurs non iOS à cause d'un bogue dans iOS Safari qui existe apparemment depuis des années. J'espère vraiment qu'ils vont régler ça pour iOS8 la semaine prochaine mais en attendant ...
Ma solution:
Certains ont déjà suggéré d'utiliser Modernizr, et bien Modernizr vous permet de créer vos propres tests. Ce que je fais ici consiste essentiellement à "abstraire" l'idée d'un navigateur qui prend en charge :hover
Dans un test Modernizr que je peux utiliser dans tout mon code sans coder en dur if (iOS)
pendant tout le processus.
Modernizr.addTest('workinghover', function ()
{
// Safari doesn't 'announce' to the world that it behaves badly with :hover
// so we have to check the userAgent
return navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? false : true;
});
Alors le css devient quelque chose comme ça
html.workinghover .rollover:hover
{
// rollover css
}
Ce test échouera uniquement sur iOS et désactivera le basculement.
La meilleure partie de cette abstraction est que si je trouve qu'il se casse sur un certain Android ou s'il est corrigé dans iOS9, je peux simplement modifier le test.
L'ajout de bibliothèque FastClick à votre page entraînera la transformation de tous les taps d'un appareil mobile en événements de clic (quel que soit l'endroit où l'utilisateur clique), ce qui devrait également résoudre le problème du survol sur les appareils mobiles. J'ai édité votre violon à titre d'exemple: http://jsfiddle.net/FvACN/8/ .
Incluez simplement la bibliothèque fastclick.min.js sur votre page et activez-la via:
FastClick.attach(document.body);
En outre, cela éliminera également le retard onClick de 300 ms qui gêne les appareils mobiles.
L'utilisation de FastClick a quelques conséquences mineures qui peuvent ou non avoir de l'importance pour votre site:
Une meilleure solution, sans vérification de JS, de classe css ni de fenêtre d'affichage: vous pouvez utiliser Interaction Media Features (Requêtes sur les médias de niveau 4)
Comme ça:
@media (hover) {
// properties
my:hover {
color: red;
}
}
iOS Safari le supporte
En savoir plus sur: https://www.jonathanfielding.com/an-inintroduction-to-interaction-media-features/
Il existe essentiellement trois scénarios:
:hover
:hover
La réponse initialement acceptée fonctionne bien si seuls les deux premiers scénarios sont possibles, où un utilisateur a un pointeur ou un écran tactile. C'était courant lorsque le PO a posé la question il y a 4 ans. Plusieurs utilisateurs ont fait remarquer que les périphériques Windows 8 et Surface rendaient le troisième scénario plus probable.
La solution iOS pour résoudre le problème de l'impossibilité de survoler les appareils à écran tactile (comme détaillé par @Zenexer) est astucieuse, mais peut entraîner un mauvais comportement du code simple (comme indiqué par l'OP). La désactivation du survol uniquement pour les appareils à écran tactile signifie que vous aurez toujours besoin de coder une alternative conviviale pour écran tactile. Détecter lorsqu'un utilisateur a à la fois un pointeur et un écran tactile perturbe encore plus les choses (comme l'explique @Simon_Weaver).
À ce stade, la solution la plus sûre consiste à éviter d'utiliser :hover
Comme seul moyen pour un utilisateur d'interagir avec votre site Web. Les effets de survol constituent un bon moyen d'indiquer qu'un lien ou un bouton peut faire l'objet d'une action, mais l'utilisateur ne devrait pas être tenu de survoler un élément pour effectuer une action sur votre site Web.
Repenser la fonctionnalité de "survol" avec les écrans tactiles à l'esprit discute bien des approches alternatives de l'expérience utilisateur. Les solutions apportées par la réponse incluent:
À l'avenir, ce sera probablement la meilleure solution pour tous les nouveaux projets. La réponse acceptée est probablement la deuxième meilleure solution, mais assurez-vous de prendre en compte les périphériques qui possèdent également des périphériques de pointeur. Veillez à ne pas éliminer les fonctionnalités lorsqu'un périphérique dispose d'un écran tactile uniquement pour contourner le hack :hover
D'iOS.
La version de JQuery dans votre fichier .css utilise .no-touch .my-element: le survol de toutes vos règles de survol inclut JQuery et le script suivant.
function removeHoverState(){
$("body").removeClass("no-touch");
}
Ensuite, dans la balise body, ajoutez class = "no-touch" ontouchstart = "removeHoverState ()"
dès que l'ontouchstart déclenche la classe pour tous les états de survol est supprimé
Merci @ Morgan Cheng pour la réponse, mais j'ai légèrement modifié la fonction JS pour obtenir le " touchstart " (code extrait de @Timothy Perez - réponse ), cependant, vous avez besoin de jQuery 1.7+ pour cela
$(document).on({ 'touchstart' : function(){
//do whatever you want here
} });
Compte tenu de la réponse fournie par Zenexer, un modèle qui ne nécessite aucune balise HTML supplémentaire est le suivant:
jQuery('a').on('mouseover', function(event) {
event.preventDefault();
// Show and hide your drop down nav or other elem
});
jQuery('a').on('click', function(event) {
if (jQuery(event.target).children('.dropdown').is(':visible') {
// Hide your dropdown nav here to unstick
}
});
Cette méthode déclenche le survol en premier, le clic en second.
Je conviens que désactiver le survol tactile est la solution.
Cependant, pour vous épargner la peine de ré-écrire votre css, enveloppez simplement les éléments :hover
Dans @supports not (-webkit-overflow-scrolling: touch) {}
.hover, .hover-iOS {
display:inline-block;
font-family:arial;
background:red;
color:white;
padding:5px;
}
.hover:hover {
cursor:pointer;
background:green;
}
.hover-iOS {
background:grey;
}
@supports not (-webkit-overflow-scrolling: touch) {
.hover-iOS:hover {
cursor:pointer;
background:blue;
}
}
<input type="text" class="hover" placeholder="Hover over me" />
<input type="text" class="hover-iOS" placeholder="Hover over me (iOS)" />
Au lieu d'avoir uniquement des effets de survol lorsque le toucher n'est pas disponible, j'ai créé un système de gestion des événements tactiles, ce qui a résolu le problème pour moi. Tout d'abord, j'ai défini un objet pour tester les événements "tap" (équivalent à "clic").
touchTester =
{
touchStarted: false
,moveLimit: 5
,moveCount: null
,isSupported: 'ontouchend' in document
,isTap: function(event)
{
if (!this.isSupported) {
return true;
}
switch (event.originalEvent.type) {
case 'touchstart':
this.touchStarted = true;
this.moveCount = 0;
return false;
case 'touchmove':
this.moveCount++;
this.touchStarted = (this.moveCount <= this.moveLimit);
return false;
case 'touchend':
var isTap = this.touchStarted;
this.touchStarted = false;
return isTap;
default:
return true;
}
}
};
Ensuite, dans mon gestionnaire d'événements, je fais quelque chose comme ceci:
$('#nav').on('click touchstart touchmove touchend', 'ul > li > a'
,function handleClick(event) {
if (!touchTester.isTap(event)) {
return true;
}
// touch was click or touch equivalent
// nromal handling goes here.
});