Come rimuovere / ignorare: passa il mouse sullo stile CSS sui dispositivi touch


141

Voglio ignorare tutte le :hoverdichiarazioni CSS se un utente visita il nostro sito Web tramite dispositivo touch. Perché il :hoverCSS non ha senso e può anche essere inquietante se un tablet lo attiva facendo clic / tocca perché potrebbe rimanere bloccato fino a quando l'elemento non perde lo stato attivo. Ad essere sincero, non so perché i dispositivi touch sentano la necessità di innescarsi :hoverin primo luogo, ma questa è la realtà, quindi anche questo problema è la realtà.

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

Quindi, (come) posso rimuovere / ignorare tutte le :hoverdichiarazioni CSS contemporaneamente (senza doverle conoscere tutte) per i dispositivi touch dopo averle dichiarate?



1
Lo aggiro con una soluzione php in cui scopro se il dispositivo di visualizzazione è mobile o meno e utilizzo il foglio di stile corretto con varie modifiche basate su quello. Questo non risponde alla tua domanda però. Potresti potenzialmente utilizzare query @media ma non è garantito che funzioni anche quando telefoni e tablet hanno risoluzioni full hd.
TomFirth,

Risposte:


171

tl; dr usa questo: https://jsfiddle.net/57tmy8j3/

Se ti interessa perché o quali altre opzioni ci sono, continua a leggere.

Quick'n'dirty: rimuovi: passa il mouse con gli stili usando JS

Puoi rimuovere tutte le regole CSS che contengono :hoverusando Javascript. Questo ha il vantaggio di non dover toccare CSS ed essere compatibile anche con i browser più vecchi.

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

if (hasTouch()) { // remove all the :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) {}
}

Limitazioni: i fogli di stile devono essere ospitati sullo stesso dominio (ciò significa che non sono presenti CDN). Disabilita i passaggi su mouse e dispositivi touch misti come Surface o iPad Pro, danneggiando la UX.

Solo CSS: utilizza le query multimediali

Inserisci tutte le tue regole: hover in un @mediablocco:

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

o in alternativa, sovrascrivere tutte le regole al passaggio del mouse (compatibile con i browser più vecchi):

a:hover { color: blue; }

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

Limitazioni: funziona solo su iOS 9.0+, Chrome per Android o Android 5.0+ quando si utilizza WebView. hover: hoverinterrompe gli effetti al passaggio del mouse sui browser più vecchi,hover: none deve sovrascrivere tutte le regole CSS precedentemente definite. Entrambi sono incompatibili con mouse e dispositivi touch misti .

Il più robusto: rileva il tocco tramite JS e antepone CSS: regole al passaggio del mouse

Questo metodo ha bisogno di anteporre tutte le regole al passaggio del mouse con body.hasHover. (o un nome di classe a tua scelta)

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

La hasHoverclasse può essere aggiunta usando hasTouch()dal primo esempio:

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

Tuttavia, ciò dovrebbe avere gli stessi inconvenienti con i dispositivi a tocco misto degli esempi precedenti, il che ci porta alla soluzione definitiva. Abilita gli effetti al passaggio del mouse ogni volta che si sposta un cursore del mouse, disabilita gli effetti al passaggio del mouse ogni volta che viene rilevato un tocco.

function watchForHover() {
  // lastTouchTime is used for ignoring emulated mousemove events
  let lastTouchTime = 0

  function enableHover() {
    if (new Date() - lastTouchTime < 500) return
    document.body.classList.add('hasHover')
  }

  function disableHover() {
    document.body.classList.remove('hasHover')
  }

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

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

  enableHover()
}

watchForHover()

Questo dovrebbe funzionare sostanzialmente in qualsiasi browser e abilitare / disabilitare gli stili al passaggio del mouse, se necessario.

Ecco l'esempio completo - moderno: https://jsfiddle.net/57tmy8j3/
Legacy (per l'utilizzo con i browser precedenti): https://jsfiddle.net/dkz17jc5/19/


Grazie! Un solo commento: non sarebbe meglio controllare prima se document.styleSheetsesiste invece di usare try/catch?
Simon Ferndriger,

1
Ho usato try/catchsolo nel caso in cui si verifichi un errore strano, che potrebbe causare l'arresto anomalo dello script, come deleteRule non funzionante a causa della politica della stessa origine o del supporto instabile su IE (modificato il commento per riflettere quello). Ma sì, nella maggior parte dei casi, basta un semplice controllo.
lama

1
Vale la pena ricordare che i browser desktop, incluso Firefox, non si tradurranno in "notouch". Riferiscono di aver compreso gli eventi tattili.
Harry B,

3
Questa soluzione non funziona per dispositivi misti in cui il passaggio del mouse deve funzionare per il mouse ma non per gli eventi touch
nbar,

2
@Haneev è corretto per la maggior parte dei casi, anche se non per quello specifico. Far funzionare la tua regola aggiungerebbe molta complessità al codice, il che renderebbe più difficile la risposta. Suggerirei di dividere le regole o di utilizzare la seconda soluzione, che è comunque più robusta. Tuttavia, sei il benvenuto a suggerire una modifica, se puoi migliorare la prima soluzione senza renderla troppo complicata.
lama

43

Adattamento puntatore al salvataggio!

Poiché questo non è stato toccato da un po 'di tempo, puoi usare:

a:link {
   color: red;
}

a:hover {
   color:blue;
}

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

Guarda questa demo sia nel browser desktop che nel browser del telefono . Supportato da moderni dispositivi touch .

Nota : tieni presente che poiché l'input principale (funzionalità) di un PC Surface è un mouse, finirà per essere un collegamento blu, anche se è uno schermo (tablet) distaccato. I browser (dovrebbero) sempre alla capacità di input più precisa.


Grazie, sarebbe conveniente! Tuttavia, l'ho provato con Chrome in modalità mobile, ma non ha funzionato - quando l'ho "toccato", è diventato blu comunque ...
Simon Ferndriger

1
@SimonFerndriger Questa è solo una limitazione degli sviluppatori Chrome. Prova ad aprire il collegamento in un vero dispositivo solo touch.
Jason T Featheringham,

1
Funziona perfettamente su iPad Chrome / Safari rispetto a OS X Chrome / Safari. Grazie! Finalmente l'elegante soluzione che vorresti per un problema visivo così piccolo.
rakaloof,

3
Ho appena provato questo sul mio attuale iPhone 6S con iOS 11 e il collegamento è diventato blu.
Lukas Petr,

1
Ho provato anche con Nexus 5X con Android 8.1.0 e Chrome 68.0.3440.91. Il collegamento è diventato blu.
Trevin Avery,

12

Ho riscontrato lo stesso problema (nel mio caso con i browser mobili Samsung) e quindi mi sono imbattuto in questa domanda.

Grazie alla risposta di Calsal ho trovato qualcosa che credo escluderebbe praticamente tutti i browser desktop perché sembra essere riconosciuto dai browser mobili che ho provato (vedi screenshot da una tabella compilata: tabella di rilevamento delle funzionalità del puntatore CSS ).

I documenti web MDN lo affermano

La funzione CSS @media del puntatore può essere utilizzata per applicare gli stili in base al fatto che il meccanismo di input principale dell'utente sia un dispositivo di puntamento e, in tal caso, quanto sia preciso

.

Quello che ho scoperto è quel puntatore: grossolano è qualcosa che è sconosciuto a tutti i browser desktop nella tabella allegata ma noto a tutti i browser mobili nella stessa tabella. Questa sembra essere la scelta più efficace perché tutti gli altri valori delle parole chiave puntatore danno risultati incoerenti.

Quindi potresti costruire una query media come quella descritta da Calsal ma leggermente modificata. Si avvale di una logica invertita per escludere tutti i dispositivi touch.

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

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

È anche descritto in questa sintesi che ho creato dopo aver studiato il problema. Codepen per la ricerca empirica.

AGGIORNAMENTO : Al momento della stesura di questo aggiornamento, 23-08-2018, e sottolineato da @DmitriPavlutin questa tecnica sembra non funzionare più con il desktop di Firefox.


Grazie @DmitriPavlutin, secondo la tabella (quando è stata compilata) dovrebbe, ma potrei dare un'altra occhiata.
Programmatore:

@DmitriPavlutin Hai davvero ragione. Aggiornerà la risposta
ProgrammerPer

1
Vuoi dire che non funziona su Firefox Desktop se utilizzato con un dispositivo esclusivamente touch? Funziona benissimo con tutto ciò che ho provato.
FuzzeeLowgeek,

@FuzzeeLowgeek Suona bene! L'ultima volta che ho controllato è stato il 23-08-2018, quindi se puoi confermarlo, forse posso aggiornare di nuovo la risposta?
Programmatore:

9

Secondo la risposta di Jason , possiamo indirizzare solo i dispositivi che non supportano il passaggio del mouse con query multimediali pure su CSS. Possiamo anche indirizzare solo dispositivi che supportano il passaggio del mouse, come la risposta di Moogal in una domanda simile, con @media not all and (hover: none). Sembra strano ma funziona.

Ne ho ricavato un mix Sass per un utilizzo più semplice:

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

Aggiornamento 2019-05-15 : Raccomando questo articolo di Medium che passa attraverso tutti i diversi dispositivi che possiamo targetizzare con i CSS. Fondamentalmente è un mix di queste regole multimediali, combinale per target specifici:

@media (hover: hover) {
    /* Device that can hover (desktops) */
}
@media (hover: none) {
    /* Device that can not hover with ease */
}
@media (pointer: coarse) {
    /* Device with limited pointing accuracy (touch) */
}
@media (pointer: fine) {
    /* Device with accurate pointing (desktop, stylus-based) */
}
@media (pointer: none) {
    /* Device with no pointing */
}

Esempio per obiettivi specifici:

@media (hover: none) and (pointer: coarse) {
    /* Smartphones and touchscreens */
}

@media (hover: hover) and (pointer: fine) {
    /* Desktops with mouse */
}

Adoro i mixin, è così che utilizzo il mio hover mixin per indirizzare solo i dispositivi che lo supportano:

@mixin on-hover {
    @media (hover: hover) and (pointer: fine) {
        &:hover {
            @content;
        }
    }
}

button {
    @include on-hover {
        color: blue;
    }
}

non funziona affatto. hai hover: nessuno nella media query per un mixin supportato da hover? hai bisogno di un puntatore: approssimativo come per l'altra risposta qui.
Allan Nienhuis,

L'hai mai provato o dici solo che non funziona perché sembra strano? Ecco perché ho scritto "Sembra strano" .. E FUNZIONA per me senza puntatore: grossolano.
Calsal,

Ho avuto alcuni risultati incoerenti con l'approccio CSS a questo sul mio OnePlus 5T (sia in Chrome che Firefix). Funzionava bene su iOS, ma non riuscivo a farlo funzionare su OnePlus. Ho testato a fondo usando any-pointer e any-hover
Zeth

6

Attualmente sto affrontando un problema simile.

Esistono immediatamente due opzioni principali : (1) controllo della stringa utente o (2) mantenimento di pagine mobili separate utilizzando un URL diverso e facendo scegliere agli utenti cosa è meglio per loro.

  1. Se sei in grado di utilizzare un linguaggio di nastro adesivo Internet come PHP o Ruby, puoi controllare la stringa utente del dispositivo che richiede una pagina e semplicemente pubblicare lo stesso contenuto ma con uno stile <link rel="mobile.css" />invece del normale.

Le stringhe utente hanno informazioni identificative su browser, renderer, sistema operativo, ecc. Spetta a te decidere quali dispositivi sono "touch" anziché non-touch. Potresti riuscire a trovare queste informazioni disponibili da qualche parte e mapparle nel tuo sistema.

R. Se ti è permesso ignorare i vecchi browser , devi solo aggiungere una singola regola al normale CSS non mobile, vale a dire: EDIT : Erk. Dopo aver fatto un po 'di sperimentazione, ho scoperto che la seguente regola disabilita anche la possibilità di seguire i collegamenti nei browser webkit oltre a causare solo la disabilitazione degli effetti estetici - vedi http://jsfiddle.net/3nkcdeao/
Come tale, avrai per essere un po 'più selettivo su come modificare le regole per il caso mobile rispetto a quello che mostro qui, ma potrebbe essere un utile punto di partenza:

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

Come sidenote, disabilitare gli eventi puntatore su un genitore e quindi abilitarli esplicitamente su un figlio fa sì che eventuali effetti hover sul genitore diventino nuovamente attivi se entra un elemento figlio :hover.
Vedere http://jsfiddle.net/38Lookhp/5/

B. Se stai supportando i renderizzatori web legacy, dovrai fare un po 'più di lavoro sulla falsariga di rimuovere eventuali regole che impostano stili speciali durante :hover. Per risparmiare tempo a tutti, potresti semplicemente voler creare un comando di copia automatica + sed che si esegue sui fogli di stile standard per creare le versioni mobili. Ciò ti consentirebbe semplicemente di scrivere / aggiornare il codice standard e cancellare tutte le regole di stile che utilizzano :hoverper la versione mobile delle tue pagine.

  1. (I) In alternativa, fai semplicemente sapere ai tuoi utenti che hai un m.website.com per dispositivi mobili oltre al tuo website.com . Sebbene il sottodominio sia il modo più comune, potresti anche avere qualche altra modifica prevedibile di un determinato URL per consentire agli utenti mobili di accedere alle pagine modificate. A quel punto, vorresti essere sicuro che non debbano modificare l'URL ogni volta che accedono a un'altra parte del sito.

Anche in questo caso, potresti essere in grado di aggiungere una o due regole extra ai fogli di stile o essere costretto a fare qualcosa di leggermente più complicato usando sed o un'utilità simile. Probabilmente sarebbe più facile da applicare: non alle tue regole di stile come quelle in div:not(.disruptive):hover {...cui aggiungeresti class="disruptive"elementi che fanno cose fastidiose per gli utenti di dispositivi mobili usando js o il linguaggio del server, invece di confondere il CSS.

  1. (II) Puoi effettivamente combinare i primi due e (se sospetti che un utente abbia vagato per la versione errata di una pagina) puoi suggerire che si spostano dentro / fuori dal display di tipo mobile o semplicemente hanno un link da qualche parte che consente agli utenti di flop avanti e indietro. Come già detto, le query @media potrebbero anche essere utili per determinare ciò che viene utilizzato per visitare.

  2. (III) Se stai cercando una soluzione jQuery una volta che sai quali dispositivi sono "touch" e quali no, potresti trovare utile il passaggio del mouse CSS che non viene ignorato sui dispositivi touch-screen .


pointer-events- è stupefacente! Questo è esattamente quello che stavo cercando, grazie mille!
Simon Ferndriger,

1
@SimonFerndriger Bene, spero che sia utile andare avanti. Assicurati di tenere presente l'avvertenza che ad oggi, i <a>link potrebbero essere inaccessibili sotto pointer-events:none. Con un po 'di fortuna, ciò cambierà in seguito - o CSS 3.xo 4.0+ avrà pointer-events:navigation-onlyo simili.
SeldomNeedy,

6

prova questo:

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

AGGIORNAMENTO: sfortunatamente W3C ha rimosso questa proprietà dalle specifiche ( https://github.com/w3c/csswg-drafts/commit/2078b46218f7462735bb0b5107c9a3e84fb4c4b1 ).


Ciò risolverebbe davvero il problema. Non ne avevo mai sentito parlare prima. In quale versione del browser dovrebbe funzionare?
Simon Ferndriger,


Bene ... Non ha un ampio supporto per il browser.
Giacomo Paita,

Questo è figo! Grazie per una soluzione così conveniente. Spero che sarà aggiunto agli standard W3C.
GProst

felice di poterti aiutare ^^
Marouen Mhiri

5

Puoi usare Modernizr JS (vedi anche questa risposta StackOverflow ) o creare una funzione JS personalizzata:

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');
} 

per rilevare il supporto dell'evento touch nel browser e quindi assegnare una CSSproprietà regolare , attraversando l'elemento con la html.no-touchclasse, in questo modo:

html.touch a {
    width: 480px;
}

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

Questo è stato suggerito anche da @blade - tuttavia, l'uso del htmltag anziché del bodytag potrebbe rendere un po 'meglio la lettura. Questa è in realtà la soluzione che sto attualmente utilizzando. Grazie lo stesso.
Simon Ferndriger,

1

Mi è stato 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");
                    }
                }
            }
        }
    }
}

1

Anche questa è una possibile soluzione alternativa, ma dovrai passare attraverso il tuo css e aggiungere un .no-touch classe prima dei tuoi stili al passaggio del mouse.

Javascript:

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

Esempio 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>

fonte

Ps Ma dovremmo ricordare, stanno arrivando sempre più dispositivi touch sul mercato, che supportano anche l'input del mouse allo stesso tempo.


0

Questa potrebbe non essere ancora una soluzione perfetta (ed è con jQuery) ma forse è una direzione / un concetto su cui lavorare: che ne dici di fare il contrario? Ciò significa disattivare gli stati: hover css per impostazione predefinita e attivarli se viene rilevato un evento mousemove in qualsiasi punto del documento. Ovviamente questo non funziona se qualcuno ha disattivato js. Cos'altro potrebbe essere contrario a farlo in questo modo?

Forse così:

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
Un problema è in realtà che è anche un .mousemove () quando si fa clic su qualcosa sui dispositivi touch.
Lars a upstruct il

1
E probabilmente attiverai questo evento ininterrottamente, con un impatto sulle prestazioni. Se questo dovesse funzionare, dovresti usarlo meglio$('body').one.('mousemove', ...)
Simon Ferndriger,

0

Prova questo (io uso lo sfondo e il colore di sfondo in questo esempio):

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

Il modo sporco ... Non elegante, ma il modo più semplice che può salvarti.

Rimuovi tutto ciò che caratterizza il passaggio del mouse.

.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

Se il tuo problema è quando tocchi / tocchi su Android e l'intero div coperto da un colore blu trasparente! Quindi devi solo cambiare il

CURSORE: PUNTATORE; al CURSORE: DEFAULT;

usa mediaQuery per nasconderti su cellulare / tablet.

Questo funziona per me.


-1

Prova questa semplice soluzione jquery 2019, anche se è in giro da un po ';

  1. aggiungi questo plugin alla testa:

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

  2. aggiungi questo a js:

    $ ("*"). on ("touchend", funzione (e) {$ (this) .focus ();}); // si applica a tutti gli elementi

  3. alcune varianti suggerite a questo sono:

    $ (": input,: checkbox,"). on ("touchend", function (e) {(this) .focus);}); // specifica gli elementi

    $ ("*"). on ("click, touchend", function (e) {$ (this) .focus ();}); // include l'evento click

    css: body {cursore: pointer; } // tocca ovunque per mettere a fuoco

Appunti

  • posizionare il plugin prima di bootstrap.js per evitare di influenzare le descrizioni dei comandi
  • testato solo su iPhone XR iOS 12.1.12 e iPad 3 iOS 9.3.5, utilizzando Safari o Chrome.

Riferimenti:

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

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


2
Nel 2019 non dovresti aver bisogno di usare jQuery: WebAPI è piuttosto potente e supporta tutte le principali funzionalità.
acme

Ya ... jQuery nel 2019? Che ne dici di un po 'di Flash? Hehehe.
remed.io
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.