: Die aktive Pseudoklasse funktioniert in mobilen Safari nicht

109

In Webkit auf iPhone / iPad / iPod wird das Festlegen des Stils für eine: aktive Pseudoklasse für ein <a>Tag nicht ausgelöst, wenn Sie auf das Element tippen. Wie kann ich das auslösen? Beispielcode:

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

Antworten:

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

Nur einmal angewendet, schien im Gegensatz zu jedem Schaltflächenelement alle Schaltflächen auf der Seite zu korrigieren. Alternativ können Sie diese kleine JS-Bibliothek namens ' Fastclick ' verwenden. Es beschleunigt Klickereignisse auf Touch-Geräten und behebt auch dieses Problem.

wilsonpage
quelle
19
Reicht es nicht aus, einfach ontouchstartohne das hinzuzufügen =""? (HTML5)
Feklee
2
Für zukünftige Leser habe ich hier eine Demo gepostet: http://jsbin.com/EjiWILe/3/ . Überprüfen Sie die Funktionalität Ihres iOS-Geräts.
Mhulse
6
Können Sie erklären, warum Sie einen leeren Hörer auf den Körper angewendet haben? Wie funktioniert es?
Maurizio Battaghini
2
Ich habe verwendet: focus, und das funktioniert auch dafür. Danke für die Magie.
TecBrat
Ich bekomme Seitenstopps unter iOS 9.1 und 9.3 mit dieser Methode ... diese Versionen hatten einen JS-Fehler, haben aber immer noch 0,5% Benutzer auf diesen Betriebssystemen
Ruskin
55

Wie in anderen Antworten angegeben, löst iOS Safari die Pseudoklasse nur aus, :activewenn dem Element ein Berührungsereignis zugeordnet ist. Bisher war dieses Verhalten jedoch "magisch". Ich bin auf diesen kleinen Klappentext in der Safari Developer Library gestoßen , der ihn erklärt (Hervorhebung von mir):

Sie können die -webkit-tap-highlight-colorCSS-Eigenschaft auch in Kombination mit dem Festlegen eines Berührungsereignisses verwenden, um Schaltflächen so zu konfigurieren, dass sie sich ähnlich wie der Desktop verhalten. Unter iOS werden Mausereignisse so schnell gesendet, dass der Status "Aus" oder "Aktiv" nie empfangen wird. Daher wird der :activePseudo-Status nur ausgelöst, wenn für das HTML-Element ein Berührungsereignis festgelegt ist, z. B. wenn für das Element ontouchstart wie folgt festgelegt ist:

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

Wenn die Schaltfläche unter iOS getippt und gehalten wird, ändert sich die Schaltfläche in die angegebene Farbe, ohne dass die umgebende transparente graue Farbe angezeigt wird.

Mit anderen Worten, das Festlegen eines ontouchstartEreignisses (auch wenn es leer ist) weist den Browser explizit an, auf Berührungsereignisse zu reagieren.

Meiner Meinung nach handelt es sich hierbei um ein fehlerhaftes Verhalten, das wahrscheinlich auf die Zeit zurückgeht, als das "mobile" Web im Grunde nicht existierte (sehen Sie sich diese Screenshots auf der verlinkten Seite an, um zu sehen, was ich meine), und alles war mausorientiert. Es ist interessant festzustellen, dass andere, neuere mobile Browser, wie z. B. Android, den Pseudo-Status ": active" bei Berührung problemlos anzeigen, ohne Hacks, wie sie für iOS erforderlich sind.

(Randnotiz: Wenn Sie unter iOS Ihre eigenen benutzerdefinierten Stile verwenden möchten, können Sie auch das standardmäßige graue durchscheinende Feld deaktivieren, das iOS anstelle des :activePseudostatus verwendet, indem Sie die -webkit-tap-highlight-colorCSS-Eigenschaft verwenden, wie auf derselben verknüpften Seite oben erläutert .)


Nach einigen Experimenten funktioniert die erwartete Lösung, ein ontouchstartEreignis für das <body>Element festzulegen, zu dem alle Berührungsereignisse sprudeln, nicht vollständig. Ist das Element im Ansichtsfenster sichtbar , wenn die Seite geladen wird , dann funktioniert es in Ordnung, aber nach unten scrollen und tippe ein Element , das in der Ansicht war aus nicht nicht löst den :activePseudostaat wie es sollte. Also statt

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

Hängen Sie das Ereignis an alle Elemente an, anstatt sich darauf zu verlassen, dass das Ereignis in den Körper sprudelt (mithilfe von jQuery):

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

Ich bin mir jedoch der Auswirkungen auf die Leistung nicht bewusst, seien Sie also vorsichtig.


BEARBEITEN: Diese Lösung weist einen schwerwiegenden Fehler auf: Selbst das Berühren eines Elements beim Scrollen der Seite aktiviert den :activePseudo-Status. Die Empfindlichkeit ist zu stark. Android löst dieses Problem, indem es eine sehr kleine Verzögerung einführt, bevor der Status angezeigt wird. Diese wird abgebrochen, wenn die Seite gescrollt wird. In Anbetracht dessen empfehle ich, dies nur für ausgewählte Elemente zu verwenden. In meinem Fall entwickle ich eine Web-App für den Einsatz vor Ort, bei der es sich im Grunde um eine Liste von Schaltflächen handelt, mit denen Sie durch Seiten navigieren und Aktionen senden können. Da die gesamte Seite in einigen Fällen so ziemlich Schaltflächen enthält, funktioniert dies bei mir nicht. Sie können jedoch :hoverstattdessen den Pseudo-Status festlegen, der ausgefüllt werden soll. Nach dem Deaktivieren der grauen Standardbox funktioniert dies einwandfrei.

user128216
quelle
6
Tolle Erklärung für das Warum und nicht nur für das Wie ! Vielen Dank!
Coderfin
6
Upvoted für das Verständnis der Entwickler, nicht nur ein "magisches" Rezept. Dies ist unendlich informativer als die anderen; Vielen Dank, dass Sie dies für uns geschrieben haben.
user508633
Upvoted für detaillierte Erklärung + Vorbehalte. Dies sollte die richtige Antwort sein.
Meister der Enten
39

Fügen Sie Ihrem <a> -Tag einen Ereignishandler für ontouchstart hinzu. Dies bewirkt, dass das CSS auf magische Weise funktioniert.

<a ontouchstart="">Click me</a>
Jesse Rusak
quelle
3
Entschuldigung, das ist eine alte Antwort, aber warum funktioniert das trotzdem? Ich habe nichts dagegen, "magisch" als Grund, aber wenn Sie erklären könnten, warum es funktioniert, würde ich gerne mehr Details lesen.
Mhulse
1
@mhulse Ich würde auch gerne wissen warum.
Jesse Rusak
Ha! Wir sind im selben Boot. Ich werde versuchen, Nachforschungen anzustellen und hier einen Link zu (halb-) offiziellen Dokumenten zu diesem Thema zu veröffentlichen. Ich liebe es, dass diese Technik funktioniert, ich frage mich nur warum?
Mhulse
7

Das funktioniert bei mir:

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

Hinweis: Wenn Sie diesen Trick ausführen, sollten Sie auch die Standardfarbe entfernen, die Mobile Safari mithilfe der folgenden CSS-Regel anzeigt.

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

Ab dem 8. Dezember 2016 <body ontouchstart="">...</body>funktioniert die akzeptierte Antwort ( ) auf Safari 10 (iPhone 5s) nicht mehr für mich: Dieser Hack funktioniert nur für die Elemente, die beim Laden der Seite sichtbar waren.

Hinzufügen von:

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

Das headfunktioniert so, wie ich es möchte, mit dem Nachteil, dass jetzt alle Berührungsereignisse während des Bildlaufs auch den :activePseudozustand der berührten Elemente auslösen . (Wenn dies ein Problem für Sie ist, können Sie die Problemumgehung von FighterJet in Betracht ziehen :hover.)

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

Dies funktioniert bei mir. Fügen Sie Ihrem CSS das Element hinzu, das Sie hervorheben möchten

Redeye
quelle
3

Verwenden Sie alle Pseudoklassen oder nur die eine? Wenn Sie mindestens zwei verwenden, stellen Sie sicher, dass sie in der richtigen Reihenfolge sind oder alle kaputt gehen:

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

..in dieser Reihenfolge. Wenn Sie nur: active verwenden, fügen Sie einen: link hinzu, auch wenn Sie ihn nicht stylen.

tahdhaze09
quelle
Toller Tipp, dass Ordnung beim Styling von Pseudoklassen wichtig ist.
Brianarpie
1

Ich habe ein Tool veröffentlicht, das dieses Problem für Sie lösen soll.

Oberflächlich betrachtet sieht das Problem einfach aus, aber in Wirklichkeit muss das Touch & Click-Verhalten ziemlich umfassend angepasst werden, einschließlich Timeout-Funktionen und Dingen wie "Was passiert, wenn Sie durch eine Liste von Links scrollen" oder "Was passiert, wenn Sie auf Link klicken und dann" Maus / Finger vom aktiven Bereich entfernen "

Dies sollte alles auf einmal lösen: https://www.npmjs.com/package/active-touch

Sie müssen entweder Ihre: aktiven Stile der .active-Klasse zuweisen oder Ihren eigenen Klassennamen auswählen. Standardmäßig funktioniert das Skript mit allen Linkelementen, Sie können es jedoch mit Ihrem eigenen Array von Selektoren überschreiben.

Ehrliches, hilfreiches Feedback und Beiträge sehr geschätzt!

dmitrizzle
quelle
2
Diese Bibliothek fügt jedem Linkelement 9 (nicht passive) Ereignis-Listener hinzu, ruft jedoch nicht removeEventListener auf - dies wäre ein großer Fehler für Anwendungen mit nur einer Seite, denke ich
Drenai,
1
Danke Ryan. Ich habe diesen Code seit über einem Jahr nicht mehr unterstützt oder verwendet. Ich werde es abnehmen. Nach einigem Nachdenken und Experimentieren habe ich das Design der App geändert, anstatt zu versuchen, Interaktionen zu erzwingen, die von Browsern nicht berücksichtigt oder durchdacht wurden.
Dmitrizzle
1

Für diejenigen, die den ontouchstart nicht verwenden möchten, können Sie diesen Code verwenden

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

Ich habe diese Antwort und ihre Varianten ausprobiert , aber keine schien zuverlässig zu funktionieren (und ich mag es nicht, mich bei solchen Dingen auf "Magie" zu verlassen). Also habe ich stattdessen Folgendes gemacht, das auf allen Plattformen perfekt funktioniert, nicht nur auf Apple:

  1. Umbenannt CSS - Deklarationen , die verwendet :activezu .active.
  2. Erstellte eine Liste aller betroffenen Elemente und fügte pointerdown/mousedown/touchstartEreignishandler hinzu , um die .activeKlassen- und pointerup/mouseup/touchendEreignishandler anzuwenden , um sie zu entfernen. Verwenden von 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');
    });

Das war ein bisschen langweilig, aber jetzt habe ich eine Lösung, die weniger anfällig für Brüche zwischen Apple OS-Versionen ist. (Und wer braucht so etwas zu brechen?)

Daffinm
quelle
Ich denke, es gibt eine Antwort auf die Frage. Es scheint keinen zuverlässigen Weg zu geben, die aktive Pseudoklasse auf mobile Safari zu bringen. Dies kann jedoch mit der von mir angegebenen Lösung zuverlässig emuliert werden. Ich habe dies in meiner App getan und es funktioniert perfekt auf allen Plattformen. Und ich habe zur Verdeutlichung Code hinzugefügt.
Daffinm
0

Eine Lösung besteht darin, sich auf :targetFolgendes zu verlassen :active:

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

Der Stil wird ausgelöst, wenn der Anker von der aktuellen URL als Ziel ausgewählt wird, die auch auf Mobilgeräten robust ist. Der Nachteil ist, dass Sie einen anderen Link benötigen, um den Anker in der URL zu löschen. Vollständiges Beispiel:

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

rgmt
quelle
-3

Keine 100% im Zusammenhang mit dieser Frage, aber Sie können CSS-Geschwister-Hack verwenden, um dies ebenfalls zu erreichen

HTML

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

SCSS

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

Wenn Sie einen reinen HTML / CSS-Tooltip verwenden möchten

span {
  display: none;
}
input {
    &:checked ~ span {
      display: block;
    }
  }
Seeliang
quelle
-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>
TroyM
quelle
1
Laut FAQ sind Unterschriften und Eigenwerbung nicht erlaubt.
LittleBobbyTables - Au Revoir