: la pseudo-classe attiva non funziona in mobile safari


109

In Webkit su iPhone / iPad / iPod, la specifica dello stile per una pseudo-classe: active per un <a>tag non si attiva quando tocchi l'elemento. Come posso fare in modo che si attivi? Codice di esempio:

<style> 
a:active { 
    background-color: red;
}
</style>
<!-- snip -->
<a href="#">Click me</a>

Risposte:


238
<body ontouchstart="">
    ...
</body>

Applicato solo una volta, al contrario di ogni elemento pulsante sembrava fissare tutti i pulsanti sulla pagina. In alternativa puoi usare questa piccola libreria JS chiamata " Fastclick ". Accelera gli eventi di clic sui dispositivi touch e si prende cura anche di questo problema.


19
Non è sufficiente aggiungere semplicemente ontouchstartsenza =""? (HTML5)
feklee

2
Per tutti i futuri lettori, ho pubblicato una demo qui: http://jsbin.com/EjiWILe/3/ . Controlla la funzionalità sul tuo dispositivo iOS.
mhulse

6
Puoi spiegare perché hai applicato al corpo un ascoltatore vuoto? Come funziona?
Maurizio Battaghini

2
Stavo usando: focus, e questo funziona anche per quello. Grazie per la magia.
TecBrat

Sto ottenendo il blocco delle pagine su iOS 9.1 e 9.3 usando questo metodo ... quelle versioni avevano un bug js, ma hanno ancora lo 0,5% di utenti su quei sistemi operativi
Ruskin

55

Come hanno affermato altre risposte, iOS Safari non attiva la :activepseudo-classe a meno che un evento di tocco non sia associato all'elemento, ma finora questo comportamento è stato "magico". Mi sono imbattuto in questo piccolo blurb sulla Safari Developer Library che lo spiega (enfasi mia):

È inoltre possibile utilizzare la -webkit-tap-highlight-colorproprietà CSS in combinazione con l'impostazione di un evento di tocco per configurare i pulsanti in modo che si comportino in modo simile al desktop. Su iOS, gli eventi del mouse vengono inviati così rapidamente che lo stato inattivo o attivo non viene mai ricevuto. Pertanto, lo :activepseudo stato viene attivato solo quando è presente un evento di tocco impostato sull'elemento HTML, ad esempio, quando ontouchstart è impostato sull'elemento come segue:

<button class="action" ontouchstart=""
        style="-webkit-tap-highlight-color: rgba(0,0,0,0);">
    Testing Touch on iOS
</button>

Ora, quando il pulsante viene toccato e tenuto premuto su iOS, il pulsante cambia nel colore specificato senza che venga visualizzato il colore grigio trasparente circostante.

In altre parole, l'impostazione di un ontouchstartevento (anche se vuoto) indica esplicitamente al browser di reagire agli eventi di tocco.

Secondo me, questo è un comportamento imperfetto e probabilmente risale al tempo in cui il web "mobile" era praticamente inesistente (dai un'occhiata a quegli screenshot sulla pagina collegata per vedere cosa intendo), e tutto era orientato al mouse. È interessante notare che altri browser mobili più recenti, come su Android, visualizzano lo pseudo-stato `: active 'al tocco perfettamente, senza alcun hack come quello necessario per iOS.

(Nota a margine: se desideri utilizzare i tuoi stili personalizzati su iOS, puoi anche disabilitare la casella grigia traslucida predefinita che iOS utilizza al posto dello :activepseudo-stato utilizzando la -webkit-tap-highlight-colorproprietà CSS, come spiegato nella stessa pagina collegata sopra .)


Dopo un po 'di sperimentazione, la soluzione prevista di impostare un ontouchstartevento <body>sull'elemento su cui tutti gli eventi di tocco si spostano poi non funziona completamente. Se l'elemento è visibile nella visualizzazione quando la pagina viene caricata, funziona correttamente, ma scorrere verso il basso e toccare un elemento che era fuori dalla visualizzazione non attiva lo :activepseudo-stato come dovrebbe. Quindi, invece di

<!DOCTYPE html>
<html><body ontouchstart></body></html>

allegare l'evento a tutti gli elementi invece di fare affidamento sull'evento che ribolle nel corpo (usando jQuery):

$('body *').on('touchstart', function (){});

Tuttavia, non sono a conoscenza delle implicazioni sulle prestazioni di questo, quindi attenzione.


EDIT: C'è un grave difetto con questa soluzione: anche toccare un elemento durante lo scorrimento della pagina attiverà lo :activestato pseudo. La sensibilità è troppo forte. Android risolve questo problema introducendo un piccolissimo ritardo prima che lo stato venga mostrato, che viene annullato se si scorre la pagina. Alla luce di ciò, suggerisco di utilizzarlo solo su elementi selezionati. Nel mio caso, sto sviluppando un'app Web da utilizzare sul campo che è fondamentalmente un elenco di pulsanti per navigare nelle pagine e inviare azioni. Poiché in alcuni casi l'intera pagina è composta da pulsanti, questo non funzionerà per me. Tuttavia, puoi impostare lo :hoverpseudo-stato per riempirlo. Dopo aver disabilitato la casella grigia predefinita, funziona perfettamente.


6
Ottima spiegazione del perché e non solo del come ! Grazie!
coderfin

6
Votato per aver dato agli sviluppatori comprensione, non solo una ricetta "magica". Questo è infinitamente più informativo degli altri; grazie per aver scritto questo per noi.
user508633

Votato per una spiegazione dettagliata + avvertimenti. Questa dovrebbe essere la risposta corretta.
Master of Ducks

39

Aggiungi un gestore di eventi per ontouchstart nel tag <a>. Questo fa sì che il CSS funzioni magicamente.

<a ontouchstart="">Click me</a>

3
Scusa, questa è una vecchia risposta, ma perché funziona? Non mi dispiace "magicamente" come motivo, ma se potessi spiegare perché funziona, mi piacerebbe leggere maggiori dettagli.
mhulse

1
@ mhulse mi piacerebbe anche sapere perché.
Jesse Rusak

Ha! Siamo nella stessa barca. Cercherò di fare qualche ricerca e di postare qui un link a documenti (semi) ufficiali sull'argomento. Adoro che questa tecnica funzioni, mi chiedo solo perché?
mhulse

7

Questo funziona per me:

document.addEventListener("touchstart", function() {},false);

Nota: se esegui questo trucco, vale anche la pena rimuovere il colore di evidenziazione del tocco predefinito applicato da Mobile Safari utilizzando la seguente regola CSS.

html {
    -webkit-tap-highlight-color: rgba(0,0,0,0);
}

5

A partire dall'8 dicembre 2016, la risposta accettata (<body ontouchstart="">...</body> ) non funziona per me su Safari 10 (iPhone 5s): questo hack funziona solo per quegli elementi che erano visibili al caricamento della pagina.

Tuttavia, aggiungendo:

<script type='application/javascript'>
  document.addEventListener("touchstart", function() {}, false);
</script>

al headfunziona come voglio, con il rovescio della medaglia che ora tutti gli eventi di tocco durante lo scorrimento attivano anche lo :activepseudo-stato sugli elementi toccati. (Se questo è un problema per te, potresti prendere in considerazione la :hover soluzione alternativa di FighterJet .)


4
//hover for ios
-webkit-tap-highlight-color: #ccc;

Per me funziona, aggiungi al tuo CSS l'elemento che vuoi evidenziare


3

Stai usando tutte le pseudo-classi o solo quella? Se ne stai utilizzando almeno due, assicurati che siano nell'ordine giusto o si rompono tutti:

a:link
a:visited
a:hover
a:active

..in questo ordine. Inoltre, se stai usando solo: active, aggiungi un: link, anche se non lo stai disegnando.


ottimo consiglio sull'importanza dell'ordine quando si disegnano pseudo classi.
brianarpie

1

Ho pubblicato uno strumento che dovrebbe risolvere questo problema per te.

In superficie il problema sembra semplice, ma in realtà il comportamento del tocco e del clic deve essere personalizzato in modo abbastanza esteso, comprese le funzioni di timeout e cose come "cosa succede quando scorri un elenco di link" o "cosa succede quando premi link e poi sposta il mouse / dito lontano dall'area attiva "

Questo dovrebbe risolverlo tutto in una volta: https://www.npmjs.com/package/active-touch

Avrai bisogno di avere i tuoi: stili attivi assegnati alla classe .active o scegliere il tuo nome di classe. Per impostazione predefinita, lo script funzionerà con tutti gli elementi di collegamento, ma è possibile sovrascriverlo con il proprio array di selettori.

Feedback onesto e utile e contributi molto apprezzati!


2
Quella libreria aggiunge 9 listener di eventi (non passivi) a ogni elemento di collegamento ma non chiama removeEventListener - questo sarebbe un grosso difetto per le applicazioni a pagina singola, penso
Drenai

1
Grazie Ryan. Non supporto o utilizzo questo codice da oltre un anno; Lo prendo io. Dopo alcune riflessioni e sperimentazioni ho cambiato il design dell'app invece di cercare di forzare le interazioni non considerate o pensate dai browser.
dmitrizzle

1

Per coloro che non vogliono utilizzare ontouchstart, è possibile utilizzare questo codice

<script>
 document.addEventListener("touchstart", function(){}, true);
</script>

1

Ho provato questa risposta e le sue varianti, ma nessuna sembrava funzionare in modo affidabile (e non mi piace fare affidamento sulla "magia" per cose come questa). Quindi ho fatto quanto segue, che funziona perfettamente su tutte le piattaforme, non solo su Apple:

  1. Dichiarazioni CSS rinominati che hanno usato :activea .active.
  2. Creato un elenco di tutti gli elementi interessati e aggiunto pointerdown/mousedown/touchstartgestori di eventi per applicare la .activeclasse e pointerup/mouseup/touchendgestori di eventi per rimuoverlo. Utilizzando jQuery:

    let controlActivationEvents = window.PointerEvent ? "pointerdown" : "touchstart mousedown";
    let controlDeactivationEvents = window.PointerEvent ? "pointerup pointerleave" : "touchend mouseup mouseleave";
    
    let clickableThings = '<comma separated list of selectors>';
    $(clickableThings).on(controlActivationEvents,function (e) {
        $(this).addClass('active');
    }).on(controlDeactivationEvents, function (e) {
        $(this).removeClass('active');
    });

Era un po 'noioso, ma ora ho una soluzione meno vulnerabile alle rotture tra le versioni del sistema operativo Apple. (E chi ha bisogno di qualcosa di simile a questa rottura?)


Penso che fornisca una risposta alla domanda. Non sembra esserci un modo affidabile per far funzionare la pseudo classe: active su Safari mobile. Ma questo può essere emulato in modo affidabile utilizzando la soluzione che ho fornito. L'ho fatto nella mia app e funziona perfettamente su tutte le piattaforme. E ho aggiunto il codice a scopo di chiarimento.
daffinm

0

Una soluzione è fare affidamento su :targetinvece di :active:

<style> 
a:target { 
    background-color: red;
}
</style>
<!-- snip -->
<a id="click-me" href="#click-me">Click me</a>

Lo stile verrà attivato quando l'ancora è mirata dall'URL corrente, che è robusto anche su dispositivi mobili. Lo svantaggio è che hai bisogno di un altro link per cancellare l'ancora nell'URL. Esempio completo:

a:target { 
    background-color: red;
}
<a id="click-me" href="#click-me">Click me</a>
<a id="clear" href="#">Clear</a>


-3

Nessun 100% correlato a questa domanda, ma puoi utilizzare anche l'hack di css sibling per ottenere questo risultato

HTML

<input tabindex="0" type="checkbox" id="145"/>
<label for="145"> info</label>
<span> sea</span>

SCSS

input {
    &:checked + label {
      background-color: red;
    }
  }

Se desideri utilizzare il tooltip puro html / css

span {
  display: none;
}
input {
    &:checked ~ span {
      display: block;
    }
  }

-6
<!DOCTYPE html>

<html lang="en">

<head>
<meta charset="utf-8">

<title></title>

<style>
        a{color: red;}
        a:hover{color: blue;}
</style>
</head>

<body>

        <div class="main" role="main">
                <a href="#">Hover</a>
        </div>

</body>
</html>

1
Secondo le FAQ, le firme e l'auto-promozione non sono consentite.
LittleBobbyTables - Au Revoir
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.