Désactiver les effets de survol sur les navigateurs mobiles

113

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 :hovereffets (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 preventDefaultn'é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, mousemoveet mouseleave.

Joe White
la source
7
@Blender, avez-vous lu la question? J'ai déjà expliqué pourquoi le sniffing user-agent est un mauvais choix.
Joe White
Hey Joe, as-tu trouvé une solution pour ça?
Ismatjon
Je cherchais ce genre de question, content de l'avoir trouvée!
agpt le
Voir aussi cette question, qui traite de la désactivation du survol sur tous les appareils tactiles, pas seulement sur les mobiles: stackoverflow.com/questions/23885255/…
lame du

Réponses:

83

Je déduis de votre question que votre effet de survol modifie le contenu de votre page. Dans ce cas, mon conseil est de:

  • Ajouter des effets de survol sur touchstart et mouseenter.
  • Retirer hover effets sur mouseleave, touchmoveetclick .

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):

  1. touchstart
  2. touchmove
  3. touchend
  4. Retard de 300 ms, où le navigateur s'assure qu'il s'agit d'un simple tap, pas d'un double tap
  5. mouseover
  6. mouseenter
    • Remarque : Si un événement mouseover, mouseenterou mousemovemodifie le contenu de la page, les événements suivants ne sont jamais déclenchés.
  7. mousemove
  8. mousedown
  9. mouseup
  10. 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:

  • Ajoutez des effets de survol surtouchstart et mouseenter.
  • Retirer les effets hover sur mouseleave, touchmoveetclick .

Notez qu'il n'y a aucune action sur touchend!

Cela fonctionne clairement pour les événements de souris: mouseenteret mouseleave(versions légèrement améliorées de mouseoveret mouseout) sont déclenchés, et ajoutez et supprimez le survol.

Si l'utilisateur est réellement clickun 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 survol touchmove.

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:

  • détection du navigateur: extrêmement sujet aux erreurs. Suppose qu'un appareil dispose d'une souris ou d'un écran tactile, alors qu'une combinaison des deux deviendra de plus en plus courante lorsque les écrans tactiles proliféreront.
  • Détection de média CSS: la seule solution CSS que je connaisse. Toujours sujet aux erreurs, et suppose toujours qu'un périphérique dispose d'une souris ou d'un tactile, alors que les deux sont possibles.
  • Émuler l'événement de clic dans 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.
  • Utilisez une variable pour supprimer les événements de souris: Ceci définit une variable dans touchendqui 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 a touchendest 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

MacFreek
la source
1
Bonne réponse. J'ai utilisé votre violon pour commencer à créer ma propre solution. Le touchend est cependant parfois nécessaire. (quand un touchmove ne s'exécute pas - c'est-à-dire lorsque l'utilisateur
quitte
Excellente réponse, mais dans la plupart des cas, je suggérerais d'utiliser touchend au lieu de touchstartdans 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)
user56reinstatemonica8
19

Comment puis-je obtenir les effets de survol lorsque j'utilise la souris, mais les supprimer lorsque j'utilise l'écran tactile?

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 :hovereffets dans votre CSS, vous pouvez spécifier différents styles pour différents médias:

@media screen { /* hover styles here */ } 

@media handheld { /* non-hover styles here */ }

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:

@media screen and (max-width:800px) { /* non-hover styles here */ }

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.

nnnnnn
la source
J'aimerais ajouter des effets de survol pour les événements de souris uniquement. Mais les événements tactiles émulent les événements de souris. Si j'accroche les événements tactiles et appelle preventDefault(), cela supprime parfois les événements de souris, mais comme je l'ai dit dans ma question, ce n'est pas fiable.
Joe White
6
En ce qui concerne les requêtes multimédias, que se passe-t-il lorsque Windows 8 sort et que les PC ont à la fois des écrans tactiles et des souris? Si l'utilisateur survole avec la souris, il verra le curseur de la souris et je veux les effets de survol; s'ils tapotent avec l'écran tactile, je ne veux pas des effets de survol. Mais je n'ai pas trouvé de moyen fiable de détecter la différence entre le toucher et la souris.
Joe White
Peut-être que les développeurs de navigateurs seront plus motivés pour rendre la détection plus cohérente une fois qu'ils auront un plus grand nombre d'utilisateurs sur des appareils tactiles et souris. Mais pour l'instant? Je ferais des suppositions en fonction de la taille de l'écran, mais il y a d'autres conseils dans les autres réponses. Désolé, je ne peux pas vous aider davantage.
nnnnnn
9

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 mobileNoHoverStatemodule suivant a une variable preventMouseover(initialement déclarée false), qui est configuré pour , truelorsqu'un utilisateur déclenche l' touchstartévénement sur un élément $target.

preventMouseoverest alors remis à falsechaque 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 mouseoverest déclenché après en touchstartraison de l'ordre dans lequel ils sont déclarés init.

var mobileNoHoverState = function() {

    var hoverClass = 'hover',
        $target = $(".foo"), 
        preventMouseover = false;

    function forTouchstart() {
        preventMouseover = true;
    }

    function forMouseover() {
        if (preventMouseover === false) {
            $(this).addClass(hoverClass);
        } else {
            preventMouseover = false;
        }
    }

    function forMouseout() {
        $(this).removeClass(hoverClass);
    }

    function init() {
        $target.on({
            touchstart  : forTouchstart,
            mouseover   : forMouseover,
            mouseout    : forMouseout
        });                
    }

    return {
        init: init
    };
}();

Le module est ensuite instancié plus loin dans la ligne:

mobileNoHoverState.init();
Walter Roman
la source
"preventMouseover est alors remis à true chaque fois que l'événement mouseover 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." - Votre code ne fait pas ça. Est-ce que je manque quelque chose?
Redtopia
@Redtopia Merci pour la tête! J'ai mis à jour la réponse avec le morceau de code qui a été laissé de côté.
Walter Roman
Vous n'avez pas besoin de points-virgules après la déclaration de fonction
nacholibre
@nacholibre Une utilisation correcte des points-virgules a été mise en place
Walter Roman
6

Je voulais vraiment une csssolution 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:

<a href="/" class="link">Home</a>

Ensuite, je peux le coiffer en toute sécurité uniquement :hoverlorsque l'appareil le prend facilement en charge avec ceci css:

@media (hover: hover) {
  .link:hover { /* hover styles */ }
}

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.

flintinatux
la source
Belle solution qui semble fonctionner lorsque vous émulez des appareils dans Chrome devtools. Mais cela ne fonctionne toujours pas pour Chrome Android :-(
Sjeiti
Je pense que c'est la solution la plus pratique et la plus correcte. J'espère qu'il sera bientôt ajouté aux normes W3C.
GProst
5

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:

(function () {
    'use strict';

    if (!('addEventListener' in window)) {
        return;
    }

    var htmlElement = document.querySelector('html');

    function touchStart () {
        document.querySelector('html').classList.remove('hover-active');

        htmlElement.removeEventListener('touchstart', touchStart);
    }

    htmlElement.addEventListener('touchstart', touchStart);
}());

HTML:

<html class="hover-active">

CSS:

.hover-active .mybutton:hover {
    box-shadow: 1px 1px 1px #000;
}
Bnaya
la source
Au lieu d'écouter un événement tactile, vous pouvez tester 'ontouchstart' in window. par exempleif ('ontouchstart' in window) document.querySelector('html').classList.remove('hover-active');
Yuval A.
@YuvalA. La raison pour laquelle j'attends l'événement tactile est qu'il existe des périphériques avec un pointeur et un support tactile, et que l'utilisateur utilise le pointeur, je ne veux pas supprimer le survol. Il est possible que l'utilisateur utilise le toucher, puis le pointeur, mais je n'ai pas grand chose à faire à ce sujet
Bnaya
2

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:

.desktopMode .someClass:hover{ color: red }
.touchMode .mainDiv { width: 100%; margin: 0; /*etc.*/ }

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.

Stein G. Strindhaug
la source
2

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.

@media only screen and (max-width:1024px) {

       #buttonOne{
            height: 44px;
        }


        #buttonOne:hover{
            display:none;
        }
}   
Idiot
la source
2

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-touchpour toutes les hoverrègles css .

const fs = require("fs");
const postcss = require("postcss");
const hoverPrfx = require("postcss-hover-prefix");

var css = fs.readFileSync(cssFileName, "utf8").toString();
postcss()
   .use(hoverPrfx("no-touch"))
   .process(css)
   .then((result) => {
      fs.writeFileSync(cssFileName, result);
   });

css

a.text-primary:hover {
  color: #62686d;
}

devient

.no-touch a.text-primary:hover {
  color: #62686d;
}

Lors de l'exécution, Modernizrajoute automatiquement des classes css àhtml balise comme celle-ci

<html class="wpfe-full-height js flexbox flexboxlegacy canvas canvastext webgl 
  no-touch 
  geolocation postmessage websqldatabase indexeddb hashchange
  history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage
  borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients
  cssreflections csstransforms csstransforms3d csstransitions fontface
  generatedcontent video audio localstorage sessionstorage webworkers
  applicationcache svg inlinesvg smil svgclippaths websocketsbinary">

Un 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

Stanislav Berkov
la source
1

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:

function removeHover() {
    var anchors = document.getElementsByTagName('a');
    for(i=0; i<anchors.length; i++) {
        anchors[i].addEventListener('touchstart', function(e){
            $('a').mouseleave();
        }, false);
    }
}
Dit Kholov
la source
JSHint dit "ne faites pas de fonctions dans une boucle".
NetOperator Wibby le
C'est un hack. Ce n'est PAS un code réutilisable qui peut être considéré comme une bonne pratique. @NetOperatorWibby
Said Kholov
Eh bien, ce n'est pas vraiment utile de publier un code qui ne peut pas être considéré comme une bonne pratique. C'est comme mettre un pansement sur une blessure au couteau.
NetOperator Wibby
1

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é :

html.touch *:hover {
    all:unset!important;
}

Mais cela a un très bon support :

html.touch *:hover {
    pointer-events: none !important;
}

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

Simon Dragsbæk
la source
0

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à!

Balach
la source
Rien de spécial sur le CSS; voir ma modification. Et j'ai déjà essayé mouseenter; pas de dé. Le fait d'appuyer déplace le "curseur invisible de la souris", de sorte qu'il déclenche mouseenteret mousemove(et mouseleavelorsque vous appuyez ailleurs).
Joe White
0

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.

if($('html').hasClass('no-touch')){
    $('.box').on("mouseenter", function(event){
            $(this).css('background-color','#0000ff')
    });
    $('.box').on("mouseleave", function(event){
            $(this).css('background-color','')
    });
}

Pour un appareil à écran tactile, les événements n'auront aucun écouteur, vous n'aurez donc aucun effet de survol lorsque vous appuyez sur.

Stanz
la source
Quand cela peut être fait avec css, n'utilisez pas javascript (jquery), c'est un gaspillage de puissance informatique
Simon Dragsbæk
1
Plus simple encore, dans votre CSS, vous pouvez définir des règles distinctes pour .touchet .no-touch. Réécrire votre réponse en CSS avec Modernizer html.no-touch .box:hover {background-color: "#0000ff"}et ne rien définir pour html.touch .box:hoverdevrait faire l'affaire, car l'OP essaie seulement d'éviter les mobiles :hover.
Walter Roman
0

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.

$(document).ready(
    function()
    {
        // insert your own selector here: maybe '.hoverable'?
        var selector = 'button, .hotspot';

        $('body')
            .on('mouseover', selector, function(){ $(this).addClass('mouseover');    })
            .on('mouseout',  selector, function(){ $(this).removeClass('mouseover'); })
            .on('click',     selector, function(){ $(this).removeClass('mouseover'); });
    }
);

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".

toon81
la source
0

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 {.

handle_css_hover_effects ()

function handle_css_hover_effects (init) {
 var init = init || {}
 var handle_touch_events = init.handle_touch_events || true
 var handle_mouse_events = init.handle_mouse_events || true
 var hover_class         = init.hover_class         || "hover"
 var delay_preferences   = init.delay_preferences   || {touch: {add: 500, remove: 500}}
 function default_handler (curobj, input_type, op) {
  var hovered_element_selector = "*" + ((op == "add") ? ":" : ("." + hover_class))
  var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll(hovered_element_selector))
  var modified_list = []
  while (true) {
   if ((curobj == null) || (curobj == document.documentElement)) break
   if (hovered_elements.indexOf(curobj) != -1) modified_list.push (curobj)
   curobj = curobj.parentNode
  }
  function do_hover_change () {modified_list.forEach (function (curobj) {curobj.classList[op](hover_class)})}
  if ((!delay_preferences[input_type]) || (!delay_preferences[input_type][op])) {
   do_hover_change ()
  } else {
   setTimeout (do_hover_change, delay_preferences[input_type][op])
  }
 }

 if (handle_mouse_events) {
  document.body.addEventListener ('mouseover' , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "add")})
  document.body.addEventListener ('mouseout'  , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
  document.body.addEventListener ('click'     , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
 }

 if (handle_touch_events) {
  document.body.addEventListener ('touchstart', function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "add")})
  document.body.addEventListener ('touchend'  , function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "remove")})
  document.body.addEventListener ('touchmove',  function (evt) {
   var curobj = evt.target
   var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll("*:hover"))
   var lastobj = null
   evt = evt.changedTouches[0]
   var elements_at_point = get_elements_at_point (evt.pageX, evt.pageY)
   // Get the last element that isn't at the current point but is still hovered over, and remove only its hover attribute.
   while (true) {
    if ((curobj == null) || (curobj == document.documentElement)) break
    if ((hovered_elements.indexOf(curobj) != -1) && (elements_at_point.indexOf(curobj) == -1)) lastobj = curobj
    curobj = curobj.parentNode
   }
   if (lastobj == null) return
   if ((!delay_preferences.touch) || (!delay_preferences.touch.remove)) {
    lastobj.classList.remove(hover_class)
   } else {
    setTimeout (function () {lastobj.classList.remove(hover_class)}, delay_preferences.touch.remove)
   }

   function get_elements_at_point (x, y) {
    var el_list = [], pe_list = []
    while (true) {
     var curobj = document.elementFromPoint(x, y)
     if ((curobj == null) || (curobj == document.documentElement)) break
     el_list.push (curobj); pe_list.push (curobj.style.pointerEvents)
     curobj.style.pointerEvents = "none"
    }
    el_list.forEach (function (current_element, i) {current_element.style.pointerEvents = pe_list[i]})
    return el_list
   }
  })
 }
}
Agamemnus
la source
0

Incluez Modernizr sur votre page et définissez plutôt vos états de survol comme ceci:

html.no-touchevents .box:hover {
    background: blue;
}
Jonathan Potter
la source
0

Bonjour personne du futur, vous voudrez probablement utiliser la requête pointeret / ou hovermédia. La handheldrequête multimédia est obsolète.

/* device is using a mouse or similar */
@media (pointer: fine) {
  a:hover {
    background: red;
  }
}
olanod
la source
-1

Essayez cette solution jquery 2019 facile, bien que cela existe depuis un certain temps;

  1. ajoutez ce plugin à la tête:

    src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"

  2. ajoutez ceci à js:

    $("*").on("touchend", function(e) { $(this).focus(); }); //applies to all elements

  3. Voici quelques variantes suggérées:

    $(":input, :checkbox,").on("touchend", function(e) {(this).focus);}); //specify elements
    
    $("*").on("click, touchend", function(e) { $(this).focus(); });  //include click event`
    
    css: body { cursor: pointer; } //touch anywhere to end a focus`

Remarques

  • placez le plugin avant bootstrap.js, le cas échéant, pour éviter d'affecter les info-bulles
  • testé uniquement sur l'iphone XR ios 12.1.12 et l'ipad 3 ios 9.3.5, en utilisant Safari ou Chrome.

Références:

https://code.jquery.com/ui/

https://api.jquery.com/category/selectors/jquery-selector-extensions/

Darren
la source