web-dev-qa-db-fra.com

Comment supprimer/ignorer: le style hover css sur les appareils tactiles

Je souhaite ignorer toutes les déclarations CSS :hover si un utilisateur visite notre site Web via un appareil tactile. Parce que le :hover CSS n’a pas de sens, et que cela peut même être dérangeant si une tablette le déclenche par un clic ou un tapotement, cela risquerait de coller jusqu’à ce que l’élément perd son focus. Pour être honnête, je ne sais pas pourquoi les appareils tactiles ressentent le besoin de déclencher :hover en premier lieu - mais c'est la réalité, alors ce problème est également une réalité.

a:hover {
   color:blue;
   border-color:green;
   // etc. > ignore all at once for touch devices
}

Alors, (comment) puis-je supprimer/ignorer toutes les déclarations CSS :hover à la fois (sans devoir les connaître) pour les appareils tactiles après les avoir déclarées?

76
Simon Ferndriger

Il existe plusieurs solutions à ce problème.

Quick'n'dirty - remove: survolez les styles avec JS

Vous pouvez supprimer toutes les règles CSS contenant :hover à l'aide de Javascript. Cela a l'avantage de ne pas avoir à toucher CSS et d'être compatible, même avec les navigateurs plus anciens.

function hasTouch() {
    return 'ontouchstart' in document.documentElement
           || navigator.maxTouchPoints > 0
           || navigator.msMaxTouchPoints > 0;
}

if (hasTouch()) { // remove all :hover stylesheets
    try { // prevent exception on browsers not supporting DOM styleSheets properly
        for (var si in document.styleSheets) {
            var styleSheet = document.styleSheets[si];
            if (!styleSheet.rules) continue;

            for (var ri = styleSheet.rules.length - 1; ri >= 0; ri--) {
                if (!styleSheet.rules[ri].selectorText) continue;

                if (styleSheet.rules[ri].selectorText.match(':hover')) {
                    styleSheet.deleteRule(ri);
                }
            }
        }
    } catch (ex) {}
}

Limitations: les feuilles de style doivent être hébergées sur le même domaine (c'est-à-dire sans CDN). Désactive les survols sur des souris et appareils tactiles mixés, comme Surface, ce qui blesse l'UX.

CSS-only - utilisez les requêtes multimédia

Placez toutes vos règles de survol dans un bloc @media:

@media (hover: hover) {
    a:hover { color: blue; }
}

ou bien remplacez toutes vos règles de survol (compatibles avec les anciens navigateurs):

a:hover { color: blue; }

@media (hover: none) {
    a:hover { color: inherit; }
}

Limitations: fonctionne uniquement avec iOS 9.0+, Chrome pour Android ou Android 5.0+ avec WebView. hover: hover interrompt les effets de survol sur les anciens navigateurs, hover: none doit remplacer toutes les règles CSS définies précédemment. Les deux sont incompatibles avec des périphériques mixtes souris/tactile.

Le plus robuste - utilisez une classe CSS spéciale et détectez le toucher via JS

Cette méthode nécessite l'ajout de body.hasHover à toutes les règles de survol. (ou un nom de classe de votre choix)

body.hasHover a:hover { color: blue; }

La classe hasHover peut être ajoutée à l'aide de hasTouch() du premier exemple:

if (!hasTouch()) {
    document.body.className += ' hasHover';
}

Cependant, cela pose le même problème avec les appareils tactiles mixtes que les exemples précédents, ce qui nous amène à la solution ultime. Activer les effets de survol chaque fois qu'un curseur de la souris est déplacé, désactiver les effets de survol chaque fois qu'une touche est détectée.

function watchForHover() {
    var hasHoverClass = false;
    var container = document.body;
    var lastTouchTime = 0;

    function enableHover() {
        // filter emulated events coming from touch events
        if (new Date() - lastTouchTime < 500) return;
        if (hasHoverClass) return;

        container.className += ' hasHover';
        hasHoverClass = true;
    }

    function disableHover() {
        if (!hasHoverClass) return;

        container.className = container.className.replace(' hasHover', '');
        hasHoverClass = false;
    }

    function updateLastTouchTime() {
        lastTouchTime = new Date();
    }

    document.addEventListener('touchstart', updateLastTouchTime, true);
    document.addEventListener('touchstart', disableHover, true);
    document.addEventListener('mousemove', enableHover, true);

    enableHover();
}

watchForHover();

Cela devrait fonctionner dans n’importe quel navigateur et activer/désactiver les styles de survol si nécessaire. Essayez-le ici: https://jsfiddle.net/dkz17jc5/19/

92
blade

Adaptation du pointeur à la rescousse!

Comme cela n'a pas été touché depuis un moment, vous pouvez utiliser:

a:link {
   color: red;
}

a:hover {
   color:blue;
}

@media (hover: none) {
   a:link {
      color: red;
   }
}

Voir cette démonstration dans les navigateurs de votre bureau et de votre téléphone }. Pris en charge par appareils tactiles modernes .

Note: N'oubliez pas que, comme la principale entrée (capacité) d'un PC Surface est une souris, le lien devient bleu, même s'il s'agit d'un écran détaché (tablette). Les navigateurs devront (devraient) toujours utiliser la capacité d'entrée la plus précise.

30

Je suis actuellement confronté à un problème similaire.

Deux options principales me sont immédiatement proposées: (1) la vérification de la chaîne utilisateur ou (2) la gestion de pages mobiles distinctes utilisant une URL différente et permettant aux utilisateurs de choisir le meilleur choix pour eux.

  1. Si vous parvenez à utiliser un langage Internet tel que PHP ou Ruby, vous pouvez vérifier la chaîne user du périphérique demandant une page et simplement servir le même contenu mais avec un <link rel="mobile.css" /> au lieu du style normal.

Les chaînes utilisateur contiennent des informations d'identification sur le navigateur, le moteur de rendu, le système d'exploitation, etc. Il vous appartient de décider quels périphériques sont "tactiles" ou non tactiles. Vous pourrez peut-être trouver cette information disponible quelque part et la mapper dans votre système.

A. Si vous êtes autorisé à ignorer les anciens navigateurs , il vous suffit d'ajouter une seule règle au fichier CSS normal non mobile, à savoir: &EACUTE;DITE: Erk. Après quelques expériences, j'ai découvert que la règle ci-dessous désactive également la possibilité de suivre les liens dans les navigateurs web, en plus de simplement désactiver les effets esthétiques - voir http://jsfiddle.net/3nkcdeao/
En tant que tel, vous devrez être un peu plus sélectif quant à la façon de modifier les règles pour le cas mobile que ce que je montre ici, mais cela peut être un point de départ utile:

* { 
    pointer-events: none !important; /* only use !important if you have to */
}

En tant que note de bas de page, désactiver les événements de pointeur sur un parent, puis les activer explicitement sur un enfant provoque actuellement l'activation de tout effet de survol sur le parent si un élément enfant entre :hover.
Voir http://jsfiddle.net/38Lookhp/5/

B. Si vous prenez en charge des moteurs de rendu Web hérités, vous devrez effectuer un peu plus de travail en supprimant les règles définissant des styles spéciaux au cours de :hover. Pour faire gagner du temps à tout le monde, vous souhaiterez peut-être simplement créer une commande de copie automatisée + sed ing que vous exécuterez sur vos feuilles de style standard pour créer les versions mobiles. Cela vous permettrait d'écrire/mettre à jour le code standard et de supprimer toutes les règles de style utilisant :hover pour la version mobile de vos pages.

  1. (I) Sinon, informez simplement vos utilisateurs que vous possédez un m.website.com pour appareils mobiles, en plus de votre website.com. Bien que le sous-domaine soit le moyen le plus courant, vous pouvez également effectuer d'autres modifications prévisibles d'une URL donnée pour permettre aux utilisateurs mobiles d'accéder aux pages modifiées. À ce stade, vous voudrez bien vous assurer qu'ils n'ont pas à modifier l'URL chaque fois qu'ils accèdent à une autre partie du site.

Ici encore, vous pourrez peut-être simplement ajouter une ou deux règles supplémentaires aux feuilles de style ou être obligé de faire quelque chose de légèrement plus compliqué en utilisant sed ou un utilitaire similaire. Ce serait probablement plus facile à appliquer: ne pas appliquer à vos règles de style telles que div:not(.disruptive):hover {... dans lesquelles vous ajouteriez class="disruptive" à des éléments agaçants pour les utilisateurs mobiles utilisant js ou la langue du serveur, au lieu de modifier le CSS.

  1. (II) Vous pouvez réellement combiner les deux premiers et (si vous pensez qu'un utilisateur a erré vers la mauvaise version d'une page), vous pouvez suggérer qu'il bascule dans l'affichage du type mobile, ou simplement un lien quelque part qui permet aux utilisateurs de flop en arrière. Comme déjà indiqué, les requêtes @media peuvent également être un outil à utiliser pour déterminer ce qui est utilisé pour visiter.

  2. (III) Si vous êtes prêt pour une solution jQuery une fois que vous savez quels périphériques sont "tactiles" et lesquels ne le sont pas, vous pouvez trouver utile _ { le survol CSS n'est pas ignoré sur les périphériques à écran tactile }.

7
SeldomNeedy

J'ai rencontré le même problème (dans mon cas, avec les navigateurs mobiles Samsung) et je suis donc tombé par hasard sur cette question. 

Grâce à réponse de Calsal , j'ai trouvé un élément qui, à mon avis, exclut pratiquement tous les navigateurs de bureau car il semble être reconnu par les navigateurs mobiles que j'ai essayés (voir la capture d'écran d'un tableau compilé: tableau de détection des fonctionnalités du pointeur CSS ).

MDN Web Docs

La fonctionnalité CSS @media du pointeur peut être utilisée pour appliquer des styles basés sur si le mécanisme de saisie principal de l'utilisateur est un périphérique de pointage, et si oui, quelle est sa précision

.

Ce que j’ai découvert, c’est que pointeur: grossier est une chose inconnue de tous les navigateurs de bureau de la table attachée, mais connue de tous les navigateurs mobiles de la même table. Cela semble être le choix le plus efficace car toutes les autres valeurs de mot clé de pointeur donnent des résultats incohérents.

Vous pouvez donc construire une requête multimédia telle que Calsal décrite mais légèrement modifiée. Il utilise une logique inversée pour éliminer tous les appareils tactiles.

Sass mixin:

@mixin hover-supported {    
    /* 
     * https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer 
     * coarse: The primary input mechanism includes a pointing device of limited accuracy.
     */
    @media not all and (pointer: coarse) {
        &:hover {
            @content;
        }
    }
}

a {
    color:green;
    border-color:blue;

    @include hover-supported() {
        color:blue;
        border-color:green;
    }
}

CSS compilé:

a {
  color: green;
  border-color: blue;
}
@media not all and (pointer: coarse) {
  a:hover {
    color: blue;
    border-color: green;
  }
}

Il est également décrit dans ce Gist que j’ai créé après avoir étudié le problème . Codepen pour des recherches empiriques.

UPDATE: Au moment de la rédaction de cette mise à jour 2018-08-23, et soulignée par @DmitriPavlutin, cette technique ne semble plus fonctionner avec le bureau Firefox.

5
ProgrammerPer

essaye ça:

@media (hover:<s>on-demand</s>) {
    button:hover {
        background-color: #color-when-NOT-touch-device;
    }
}

UPDATE: Malheureusement, le W3C a supprimé cette propriété des spécifications ( https://github.com/w3c/csswg-drafts/commit/2078b46218f7462735bb0b5107c9a3e84fb4c4b1 ).

5
Marouen Mhiri

Vous pouvez utiliser Modernizr JS (voir aussi ceci StackOverflow answer ), ou créer une fonction JS personnalisée:

function is_touch_device() {
 return 'ontouchstart' in window        // works on most browsers 
  || navigator.maxTouchPoints;       // works on IE10/11 and Surface
};

if ( is_touch_device() ) {
  $('html').addClass('touch');
} else {
  $('html').addClass('no-touch');
} 

pour détecter la prise en charge de l'événement touch dans le navigateur, puis affecter une propriété CSS régulière, traversant l'élément avec la classe html.no-touch, comme suit:

html.touch a {
    width: 480px;
}

/* FOR THE DESKTOP, SET THE HOVER STATE */
html.no-touch a:hover {
   width: auto;
   color:blue;
   border-color:green;
}
4
Giacomo Paita

Selon La réponse de Jason nous ne pouvons traiter que les périphériques qui ne prennent pas en charge le survol avec des requêtes de média css pur. Nous pouvons également ne traiter que les appareils compatibles avec le survol, comme la réponse de moogal dans une question similaire, avec @media not all and (hover: none). Ça a l'air bizarre mais ça marche.

J'ai fait un mix Sass à partir de cela pour une utilisation plus facile:

@mixin hover-supported {
    @media not all and (hover: none) {
        &:hover {
            @content;
        }
    }
}

Ce qui suit changerait la couleur de fond de .container du rouge au bleu en survol pour les périphériques qui le prennent en charge et restait rouge pour les périphériques tactiles:

.container {
    background-color: red;

    @include hover-supported() {
        background-color: blue;
    }
}
1
Calsal

C'est également une solution de contournement possible, mais vous devrez parcourir votre css et ajouter une classe .no-touch avant vos styles de survol.

Javascript:

if (!("ontouchstart" in document.documentElement)) {
document.documentElement.className += " no-touch";
}

Exemple CSS:

<style>
p span {
    display: none;
}

.no-touch p:hover span {
    display: inline;
}
</style>
<p><a href="/">Tap me</a><span>You tapped!</span></p>

La source

P.s. Mais rappelons-nous que de plus en plus d'appareils tactiles arrivent sur le marché, qui prennent également en charge la saisie de la souris en même temps. 

1
mr.mii

Cela n’est peut-être pas encore la solution parfaite (et c’est avec jQuery), mais c’est peut-être une direction/un concept sur lequel il faut travailler: qu’en est-il de le faire dans l’inverse? Ce qui signifie que vous devez désactiver les états: hover css par défaut et les activer si un événement mousemove est détecté n'importe où sur le document. Bien sûr cela ne fonctionne pas si quelqu'un a désactivé js. Quoi d'autre pourrait parler contre le faire de cette façon?

Peut-être comme ça:

CSS:

/* will only work if html has class "mousedetected" */
html.mousedetected a:hover {
   color:blue;
   border-color:green;
}

jQuery:

/* adds "mousedetected" class to html element if mouse moves (which should never happen on touch-only devices shouldn’t it?) */
$("body").mousemove( function() {
    $("html").addClass("mousedetected");
});
1
lars at upstruct

Le sale chemin ... Pas élégant, mais le moyen le plus simple de vous sauver la vie.

Supprimez tout ce qui caractérise le vol stationnaire.

.your-class:hover:before {
  color: blue;
  background: linear-gradient(to bottom, rgba(231,56,39,0) 0%, #aaaaaa 100%);
}

@media all and (min-width:320px) and (max-width: 960px) {
    .your-class:hover:before {
    color: black;
    background: transparent;
  }
}
0
Fellipe Sanches

Cela m'a été utile: link

function hoverTouchUnstick() {
    // Check if the device supports touch events
    if('ontouchstart' in document.documentElement) {
        // Loop through each stylesheet
        for(var sheetI = document.styleSheets.length - 1; sheetI >= 0; sheetI--) {
            var sheet = document.styleSheets[sheetI];
            // Verify if cssRules exists in sheet
            if(sheet.cssRules) {
                // Loop through each rule in sheet
                for(var ruleI = sheet.cssRules.length - 1; ruleI >= 0; ruleI--) {
                    var rule = sheet.cssRules[ruleI];
                    // Verify rule has selector text
                    if(rule.selectorText) {
                        // Replace hover psuedo-class with active psuedo-class
                        rule.selectorText = rule.selectorText.replace(":hover", ":active");
                    }
                }
            }
        }
    }
}
0
mineroot

Essayez ceci (j'utilise background et background-color dans cet exemple):

var ClickEventType = ((document.ontouchstart !== null) ? 'click' : 'touchstart');

if (ClickEventType == 'touchstart') {
            $('a').each(function() { // save original..
                var back_color = $(this).css('background-color');
                var background = $(this).css('background');
                $(this).attr('data-back_color', back_color);
                $(this).attr('data-background', background);
            });

            $('a').on('touchend', function(e) { // overwrite with original style..
                var background = $(this).attr('data-background');
                var back_color = $(this).attr('data-back_color');
                if (back_color != undefined) {
                    $(this).css({'background-color': back_color});
                }
                if (background != undefined) {
                    $(this).css({'background': background});
                }
            }).on('touchstart', function(e) { // clear added stlye="" elements..
                $(this).css({'background': '', 'background-color': ''});
            });
}

css:

a {
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
0
HU TanKy

Essayez cette solution simple, Jquery 2019, même si cela fait longtemps;

  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", fonction (e) {$ (this) .focus ();}); // s'applique à tous les éléments

  3. voici quelques variantes suggérées:

    $ (": input,: case à cocher,"). on ("touchend", fonction (e) {(this) .focus);}); // spécifie des éléments

    $ ("*"). sur ("cliquez, appuyez sur", fonction (e) {$ (this) .focus ();}); // inclure l'événement click

    css: body {curseur: pointeur; } // touchez n'importe où pour terminer un focus

Remarques 

  • place le plugin avant bootstrap.js afin d'éviter d'affecter les info-bulles
  • testé uniquement sur iphone XR ios 12.1.12 et ipad 3 ios 9.3.5, avec Safari ou Chrome.

Références:

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

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

0
darren