J'écris un site Web destiné à être utilisé à la fois sur des ordinateurs de bureau et des tablettes. Lorsqu'il est visité depuis un bureau, je veux que les zones cliquables de l'écran s'allument avec des :hover
effets (couleur d'arrière-plan différente, etc.) Avec une tablette, il n'y a pas de souris, donc je ne veux pas d'effets de survol.
Le problème est que lorsque je touche quelque chose sur la tablette, le navigateur a évidemment une sorte de "curseur de souris invisible" qui se déplace vers l'emplacement que j'ai tapé, puis le laisse là - donc la chose que je viens d'appuyer s'allume avec un effet de survol jusqu'à ce que je touche autre chose.
Comment puis-je obtenir les effets de survol lorsque j'utilise la souris, mais les supprimer lorsque j'utilise l'écran tactile?
Au cas où quelqu'un penserait à le suggérer, je ne veux pas utiliser le sniffing user-agent. Le même appareil pourrait avoir à la fois un écran tactile et une souris (peut-être pas si courant aujourd'hui, mais bien plus encore à l'avenir). Je ne suis pas intéressé par l'appareil, je suis intéressé par la façon dont il est actuellement utilisé: souris ou écran tactile.
Je l' ai déjà essayé accrocher les touchstart
, touchmove
, et les touchend
événements et appelant preventDefault()
à tous, qui ne supprime la « invisible curseur de la souris » de temps en temps; mais si je tape rapidement dans les deux sens entre deux éléments différents, après quelques tapotements, il commencera à déplacer le "curseur de la souris" et à allumer les effets de survol de toute façon - c'est comme si mon preventDefault
n'était pas toujours honoré. Je ne vous ennuierai pas avec les détails sauf si nécessaire - je ne suis même pas sûr que ce soit la bonne approche à adopter; si quelqu'un a une solution plus simple, je suis toute oreille.
Edit: Cela peut être reproduit avec du CSS standard :hover
, mais voici une rapide repro pour référence.
<style>
.box { border: 1px solid black; width: 150px; height: 150px; }
.box:hover { background: blue; }
</style>
<div class="box"></div>
<div class="box"></div>
Si vous passez la souris sur l'une des cases, il obtiendra un arrière-plan bleu, ce que je veux. Mais si vous appuyez sur l'une des cases, cela obtiendra également un fond bleu, ce que j'essaie d'éviter.
J'ai également publié ici un exemple qui fait ce qui précède et qui accroche également les événements de souris de jQuery. Vous pouvez l'utiliser pour voir que les événements tap se déclencheront également mouseenter
, mousemove
et mouseleave
.
la source
Réponses:
Je déduis de votre question que votre effet de survol modifie le contenu de votre page. Dans ce cas, mon conseil est de:
touchstart
etmouseenter
.mouseleave
,touchmove
etclick
.Vous pouvez également modifier votre page pour qu'il n'y ait pas de changement de contenu.
Contexte
Afin de simuler une souris, les navigateurs tels que Webkit mobile déclenchent les événements suivants si un utilisateur touche et relâche un doigt sur l'écran tactile (comme l'iPad) (source: Touch And Mouse sur html5rocks.com):
touchstart
touchmove
touchend
mouseover
mouseenter
mouseover
,mouseenter
oumousemove
modifie le contenu de la page, les événements suivants ne sont jamais déclenchés.mousemove
mousedown
mouseup
click
Il ne semble pas possible de dire simplement au navigateur Web de sauter les événements de la souris.
Pire encore, si un événement mouseover modifie le contenu de la page, l'événement click n'est jamais déclenché, comme expliqué dans Safari Web Content Guide - Handling Events , en particulier la figure 6.4 dans One-Finger Events . Ce qu'est exactement un «changement de contenu» dépendra du navigateur et de la version. J'ai constaté que pour iOS 7.0, un changement de couleur d'arrière-plan n'est pas (ou plus?) Un changement de contenu.
Solution expliquée
Récapituler:
touchstart
etmouseenter
.mouseleave
,touchmove
etclick
.Notez qu'il n'y a aucune action sur
touchend
!Cela fonctionne clairement pour les événements de souris:
mouseenter
etmouseleave
(versions légèrement améliorées demouseover
etmouseout
) sont déclenchés, et ajoutez et supprimez le survol.Si l'utilisateur est réellement
click
un lien, l'effet de survol est également supprimé. Cela garantit qu'il est supprimé si l'utilisateur appuie sur le bouton de retour dans le navigateur Web.Cela fonctionne également pour les événements tactiles: au démarrage tactile, l'effet de survol est ajouté. Il n'est "" pas "" supprimé au contact. Il est ajouté à nouveau
mouseenter
, et comme cela n'entraîne aucun changement de contenu (il a déjà été ajouté), l'click
événement est également déclenché et le lien est suivi sans que l'utilisateur ait besoin de cliquer à nouveau!Le délai de 300 ms qu'un navigateur a entre un
touchstart
événement etclick
est effectivement utilisé à bon escient car l'effet de survol sera affiché pendant ce court laps de temps.Si l'utilisateur décide d'annuler le clic, un mouvement du doigt le fera comme d'habitude. Normalement, c'est un problème car aucun
mouseleave
événement n'est déclenché et l'effet de survol reste en place. Heureusement, cela peut facilement être résolu en supprimant l'effet de survoltouchmove
.C'est tout!
Notez qu'il est possible de supprimer le délai de 300 ms, par exemple en utilisant la librairie FastClick , mais cela est hors de portée pour cette question.
Solutions alternatives
J'ai trouvé les problèmes suivants avec les alternatives suivantes:
touchend
: Cela suivra incorrectement le lien, même si l'utilisateur voulait uniquement faire défiler ou zoomer, sans l'intention de cliquer réellement sur le lien.touchend
qui est utilisée comme condition if dans les événements de souris suivants pour empêcher les changements d'état à ce moment-là. La variable est réinitialisée dans l'événement de clic. Voir la réponse de Walter Roman sur cette page. C'est une solution décente si vous ne voulez vraiment pas d'effet de survol sur les interfaces tactiles. Malheureusement, cela ne fonctionne pas si atouchend
est déclenché pour une autre raison et qu'aucun événement de clic n'est déclenché (par exemple, l'utilisateur a fait défiler ou zoomé), et tente par la suite de suivre le lien avec une souris (c'est-à-dire sur un appareil avec à la fois une souris et une interface tactile ).Lectures complémentaires
mouseover
oumousemove
.la source
touchend
au lieu detouchstart
dans la plupart des cas pour éviter de déclencher des actions immédiatement lorsque l'utilisateur essaie de faire défiler une page vers le haut ou vers le bas. Cela se produira toujours mais est moins susceptible de distraire ou de confondre (en supposant que c'est quelque chose d'inoffensif comme afficher une étiquette, pas quelque chose dont l'utilisateur a besoin de savoir s'est produit)Peut-être ne pensez-vous pas autant à la suppression des effets de survol pour les écrans tactiles, mais à l'ajout d'effets de survol pour les événements de souris?
Si vous souhaitez conserver les
:hover
effets dans votre CSS, vous pouvez spécifier différents styles pour différents médias:Sauf que malheureusement, il existe de nombreux appareils mobiles qui ignorent cela et utilisent simplement les règles de l'écran. Heureusement, de nombreux navigateurs mobiles / tablettes plus récents prennent en charge certaines requêtes multimédias plus sophistiquées:
Donc, même si la partie "écran" ou "portable" est ignorée, la "largeur max" fera l'affaire pour vous. Vous pouvez simplement supposer que tout ce qui a un écran inférieur à 800 pixels doit être une tablette ou un téléphone et ne pas utiliser d'effets de survol. Pour les rares utilisateurs qui utilisent une souris sur un appareil basse résolution, ils ne verront pas les effets de survol, mais votre site irait bien autrement.
Lectures complémentaires sur les requêtes des médias? Il existe de nombreux articles à ce sujet en ligne - en voici un: http://www.alistapart.com/articles/return-of-the-mobile-stylesheet
Si vous déplacez les effets de survol hors de votre CSS et que vous les appliquez avec JavaScript, vous pouvez vous lier spécifiquement aux événements de la souris, et / ou encore une fois, vous pouvez simplement faire des hypothèses en fonction de la taille de l'écran, le pire des cas étant que certains l'utilisateur qui utilise une souris manque les effets de survol.
la source
preventDefault()
, cela supprime parfois les événements de souris, mais comme je l'ai dit dans ma question, ce n'est pas fiable.J'ai écrit le JS suivant pour un projet récent, qui était un site de bureau / mobile / tablette qui a des effets de survol qui ne devraient pas apparaître au toucher.
Le
mobileNoHoverState
module suivant a une variablepreventMouseover
(initialement déclaréefalse
), qui est configuré pour ,true
lorsqu'un utilisateur déclenche l'touchstart
événement sur un élément$target
.preventMouseover
est alors remis àfalse
chaque fois que l'mouseover
événement est déclenché, ce qui permet au site de fonctionner comme prévu si un utilisateur utilise à la fois son écran tactile et sa souris.Nous savons que cela
mouseover
est déclenché après entouchstart
raison de l'ordre dans lequel ils sont déclarésinit
.Le module est ensuite instancié plus loin dans la ligne:
la source
Je voulais vraiment une
css
solution pure à cela moi-même, car saupoudrer une solution javascript pesante autour de tous mes points de vue semblait être une option désagréable. Enfin trouvé la requête @ media.hover , qui peut détecter "si le mécanisme d'entrée principal permet à l'utilisateur de survoler les éléments." Cela évite les appareils tactiles où le «survol» est plus une action émulée qu'une capacité directe du périphérique d'entrée.Donc par exemple, si j'ai un lien:
Ensuite, je peux le coiffer en toute sécurité uniquement
:hover
lorsque l'appareil le prend facilement en charge avec cecicss
:Alors que la plupart des navigateurs modernes prennent en charge les requêtes de fonctionnalités de média d'interaction, certains navigateurs populaires tels que IE et Firefox ne le font pas. Dans mon cas, cela fonctionne bien, car je voulais uniquement prendre en charge Chrome sur le bureau et Chrome et Safari sur mobile.
la source
Ma solution consiste à ajouter une classe css active au survol à la balise HTML et à l'utiliser au début de tous les sélecteurs CSS avec: hover et supprimer cette classe au premier événement touchstart.
http://codepen.io/Bnaya/pen/EoJlb
JS:
HTML:
CSS:
la source
'ontouchstart' in window
. par exempleif ('ontouchstart' in window) document.querySelector('html').classList.remove('hover-active');
Ce que j'ai fait pour résoudre le même problème est d'avoir une détection de fonctionnalité (j'utilise quelque chose comme ce code ), voir si onTouchMove est défini, et si c'est le cas, j'ajoute la classe css "touchMode" au corps, sinon j'ajoute " desktopMode ".
Ensuite, chaque fois qu'un effet de style s'applique uniquement à un périphérique tactile, ou uniquement à un bureau, la règle css est précédée de la classe appropriée:
Edit : Cette stratégie ajoute bien sûr quelques caractères supplémentaires à votre css, donc si vous êtes préoccupé par la taille du css, vous pouvez rechercher les définitions touchMode et desktopMode et les mettre dans des fichiers différents, afin que vous puissiez servir des css optimisés pour chaque appareil type; ou vous pouvez changer les noms de classe en quelque chose de beaucoup plus court avant de commencer à produire.
la source
Bon, j'ai eu un problème similaire mais j'ai réussi à le résoudre avec des requêtes multimédias et un CSS simple. Je suis sûr que j'enfreins certaines règles ici, mais cela fonctionne pour moi.
Je devais essentiellement prendre une application massive que quelqu'un avait faite et la rendre réactive. Ils ont utilisé jQueryUI et m'ont demandé de ne modifier aucun de leurs jQuery, j'ai donc été limité à utiliser uniquement CSS.
Lorsque j'ai appuyé sur l'un de leurs boutons en mode écran tactile, l'effet de survol se déclencherait pendant une seconde avant que l'action du bouton ne prenne effet. Voici comment je l'ai résolu.
la source
Dans mon projet, nous avons résolu ce problème en utilisant https://www.npmjs.com/package/postcss-hover-prefix et https://modernizr.com/ Nous post-traitons d'abord les fichiers css de sortie avec
postcss-hover-prefix
. Il ajoute.no-touch
pour toutes leshover
règles css .css
devient
Lors de l'exécution,
Modernizr
ajoute automatiquement des classes css àhtml
balise comme celle-ciUn tel post-traitement de css plus Modernizr désactive le survol pour les appareils tactiles et l'active pour les autres. En fait, cette approche a été inspirée par Bootstrap 4, comment ils résolvent le même problème: https://v4-alpha.getbootstrap.com/getting-started/browsers-devices/#sticky-hoverfocus-on-mobile
la source
Vous pouvez déclencher l'
mouseLeave
événement chaque fois que vous touchez un élément sur l'écran tactile. Voici une solution pour toutes les<a>
balises:la source
Iv avait trouvé 2 solutions au problème, ce qui impliquait que vous détectiez le contact avec modernizr ou autre chose et définissiez une classe tactile sur l'élément html.
C'est bien mais pas très bien supporté :
Mais cela a un très bon support :
Fonctionne parfaitement pour moi, cela fait que tous les effets de survol sont comme lorsque vous appuyez sur un bouton, il s'allumera mais ne finira pas par boguer comme effet de survol initial pour les événements de souris.
Détecter le toucher des appareils sans contact Je pense que modernizr a fait le meilleur travail:https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.jsÉDITER
J'ai trouvé une solution meilleure et plus simple à ce problème
Comment déterminer si le client est un appareil tactile
la source
Il peut être utile de voir votre CSS, car cela semble être un problème plutôt étrange. Mais de toute façon, si cela se produit et que tout le reste est bon, vous pouvez essayer de déplacer l'effet de survol vers javascript (vous pouvez également utiliser jquery). Reliez simplement à l'événement mouseover ou mieux encore mouseenter et allumez votre élément lorsque l'événement se déclenche.
Consultez le dernier exemple ici: http://api.jquery.com/mouseover/ , vous pouvez utiliser quelque chose de similaire pour enregistrer le déclenchement de l'événement et le prendre à partir de là!
la source
mouseenter
; pas de dé. Le fait d'appuyer déplace le "curseur invisible de la souris", de sorte qu'il déclenchemouseenter
etmousemove
(etmouseleave
lorsque vous appuyez ailleurs).Si vous êtes satisfait d'utiliser JavaScript, vous pouvez utiliser Modernizr dans votre page. Lorsque la page se charge, un navigateur à écran non tactile aura la classe '.no-touch' ajoutée à la balise html, mais pour un navigateur à écran tactile, la balise html aura la classe '.touch' ajoutée à la balise html .
Ensuite, il s'agit simplement de vérifier si la balise html a la classe sans contact avant de décider d'ajouter vos écouteurs mouseenter et mouseleave.
Pour un appareil à écran tactile, les événements n'auront aucun écouteur, vous n'aurez donc aucun effet de survol lorsque vous appuyez sur.
la source
.touch
et.no-touch
. Réécrire votre réponse en CSS avec Modernizerhtml.no-touch .box:hover {background-color: "#0000ff"}
et ne rien définir pourhtml.touch .box:hover
devrait faire l'affaire, car l'OP essaie seulement d'éviter les mobiles:hover
.Dans un projet que j'ai réalisé récemment, j'ai résolu ce problème avec la fonctionnalité d'événements délégués de jQuery. Il recherche certains éléments à l'aide d'un sélecteur jQuery, et ajoute / supprime une classe CSS à ces éléments lorsque la souris est sur l'élément. Cela semble bien fonctionner dans la mesure où j'ai pu le tester, ce qui inclut IE10 sur un ordinateur portable tactile fonctionnant sous Windows 8.
edit: cette solution nécessite bien sûr que vous modifiiez votre CSS pour supprimer les sélecteurs ": hover", et que vous envisagiez à l'avance sur quels éléments vous voulez être "hoverable".
Si vous avez de très nombreux éléments sur votre page (comme plusieurs milliers), cela peut devenir un peu lent, car cette solution détecte les événements de trois types sur tous les éléments de la page, puis fait son travail si le sélecteur correspond. J'ai nommé la classe CSS "mouseover" au lieu de "hover", car je ne voulais pas que les lecteurs CSS lisent ": hover" là où j'ai écrit ".hover".
la source
Voici ma solution: http://jsfiddle.net/agamemnus/g56aw709/-- code ci-dessous.
Il suffit de convertir leur ": hover" en ".hover" ... c'est tout! La grande différence entre ceci et le reste est que cela fonctionnera également sur des sélecteurs d'éléments non singuliers tels que
.my_class > *:hover {
.la source
Incluez Modernizr sur votre page et définissez plutôt vos états de survol comme ceci:
la source
Bonjour personne du futur, vous voudrez probablement utiliser la requête
pointer
et / ouhover
média. Lahandheld
requête multimédia est obsolète.la source
Essayez cette solution jquery 2019 facile, bien que cela existe depuis un certain temps;
ajoutez ce plugin à la tête:
src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"
ajoutez ceci à js:
$("*").on("touchend", function(e) { $(this).focus(); }); //applies to all elements
Voici quelques variantes suggérées:
Remarques
Références:
https://code.jquery.com/ui/
https://api.jquery.com/category/selectors/jquery-selector-extensions/
la source