Vor ein paar Tagen hatten wir auf ShopTalk eine Frage zu ganz normalen Anker-Links auf iOS, und einer seltsamen Situation, in der man sie nicht einfach einmal antippen konnte, um zum Link zu gelangen, sondern man musste den Link zweimal antippen. Ich habe das selbst erlebt und war ziemlich ratlos.
Mein erster Gedanke war, dass irgendetwas Seltsames und Unerwartetes mit JavaScript passiert. Vielleicht ein Click-Handler mit preventDefault() beim ersten Klick, der dann entfernt wird. Ich konnte jedoch nichts Derartiges finden. Ich bin sicher, ich habe noch ein paar Dinge ausprobiert, aber letztendlich aufgegeben und FastClick verwendet, um sicherzustellen, dass diese Link-Klicks funktionieren. FastClick war nicht dazu gedacht, dieses Problem zu lösen, sondern eher die 300-ms-Verzögerung beim Tippen auf Links zu beheben, die einige mobile Browser auferlegen, damit sie warten können, um zu sehen, ob Sie doppelt tippen (Hinweis: kein so großes Problem mehr wie früher). Nicht ganz das richtige Werkzeug für die Aufgabe, aber es hat funktioniert.
Die Sache ist, es war überhaupt kein JavaScript-Problem, sondern ein CSS-Problem.
Nicholas C. Zakas hat dies vor langer Zeit dokumentiert
Hier haben die Leute bei Apple vielleicht ein bisschen zu schlau gedacht. Sie erkannten, dass viele Web-Funktionen auf Hover-Zuständen basierten, und fanden daher einen Weg, damit in Safari für iOS umzugehen. Wenn Sie einen Gegenstand auf einer Webseite berühren, wird zuerst ein Hover-Zustand ausgelöst und dann der „Klick“. Das Endergebnis ist, dass Sie für eine Sekunde Stile sehen, die mit :hover angewendet wurden, bevor die Klick-Interaktion stattfindet. Es ist ein wenig beunruhigend, aber es funktioniert. Safari unter iOS achtet also sehr auf Ihre Stile, die :hover im Selektor haben. Sie werden nicht einfach ignoriert.
(Danke an Pete Droll, der mich darauf aufmerksam gemacht hat.)
Hier sind zwei Zeilen CSS, die das Problem verursachen
a::after {
display: none;
content: "pseudo block!";
}
a:hover::after {
display: inline;
}
Auf einem Browser mit einem Cursor-Zeiger sehen Sie das Pseudoelement, das bei :hover angezeigt wird

Aber das Anklicken dieses Links verhindert nicht, dass der Link aufgerufen wird. Unter iOS wird beim Tippen auf den Link nur das Pseudoelement angezeigt. Es erfordert einen zweiten Tipp, um tatsächlich zum Link zu gelangen.

Android scheint das nicht zu tun. Es zeigt das Pseudoelement schnell an, aber ruft den Link auch normal auf.

Diese Sache mit dem Hinzufügen eines Pseudoelements zu einem Link... nicht sehr üblich, oder? Ich würde sagen, das stimmt, es ist nicht sehr verbreitet. Was erklärt, warum dies nicht so bekannt ist, wie wir denken, und nur ab und zu Leute erwischt.
Ich habe gesehen, wie Leute Pseudoelemente für ästhetische Zwecke verwendet haben, wie z. B. das Hinzufügen einer besser kontrollierten Unterstreichung zu Text. Wenn das also nur bei :hover passiert, blammo, ist das Problem da. Es scheint übrigens nur bei Hover aufzutreten, nicht bei Focus oder Active.
Update Dezember 2019: Beim Testen der Demo hier in Safari/iOS 13 scheint das Pseudoelement kurz aufzutauchen, dann wird der Link aufgerufen, ohne dass ein Doppeltippen erforderlich ist. Ich habe noch keine tiefergehenden Tests auf mobilen Plattformen durchgeführt.
Es sind nicht nur Pseudoelemente
Das gilt für jedes Kind-Element. Denken Sie daran, dass der Gedanke dahinter Situationen waren, in denen zusätzliche Inhalte nur bei Hover angezeigt wurden. Wahrscheinlich ist es üblicher, dass ein tatsächliches Element verwendet wird.
Zum Beispiel:
...
<li>
<a href="#0">I'm a thing in a list</a>
<span class="controls">
<button>Do Something</button>
</span>
</li>
...
li .controls {
visibility: hidden;
}
li:hover .controls {
visibility: visible;
}
Wenn über das Listenelement gehovert wird, werden einige Steuerelemente angezeigt. Da ein *Elternelement* nun einen Hover-Zustand hat, der Inhalte anzeigt, wird der Anker-Link daran gehindert, mit einem einzigen Tippen zu funktionieren.
Es muss nicht der Elter sein, es kann der Link selbst sein
<a href="http://link.com">
Link
<span>Extra Stuff</span>
</a>
a span {
display: none;
}
a:hover span {
display: inline-block;
}
Hilfe durch Media Queries
Es ist verlockend, zu denken... OK, ich werde diese Hovers nur auf „Desktop“-Websites anwenden und eine Media Query wie diese verwenden...
@media (min-width: 500px) {
a span {
display: none;
}
a:hover span {
display: inline-block;
}
}
...was in einfachen Tests funktioniert, aber die Breite des Browserfensters ist nicht die beste Methode, um zu testen, ob Sie einen Cursor und „normale“ Hovers zur Verfügung haben.
Glücklicherweise gibt es eine Media Query für Zeiger, die für uns nützlich sein könnte
@media (pointer: fine) {
a span {
display: none;
}
a:hover span {
display: inline-block;
}
}
Cool.
Es gibt auch eine Spezifikation für eine direkte Hover-Media-Query
@media (hover) {
}
Beide Arten von Media Queries funktionierten bei mir in Chrome und Safari, aber nicht in Firefox (Support-Level-Diagramm), was sie ein bisschen zu riskant zu verwenden macht, vielleicht. Selbst JavaScript-Methoden zur Erkennung von Touch sind fragwürdig, höre ich, und werden immer seltsam falsch sein auf Geräten, die beides unterstützen.
UPDATE März 2019: Firefox 64 wurde im Dezember 2018 veröffentlicht und enthielt Unterstützung für Hover-Media-Queries, wodurch die Support-Übersicht für diese erheblich verbessert wurde. Das ist wahrscheinlich die beste Lösung.
Es ist wahrscheinlich am besten, sich einfach nicht darauf zu verlassen, dass Hover etwas anzeigt
Die Technologie, um dies zu umgehen, ist noch nicht ganz ausgereift.
Gestalten Sie Ihre Website im Zweifelsfall so, dass Klicks oder Taps erforderlich sind, um andere Dinge anzuzeigen, aber machen Sie dies so offensichtlich wie möglich und sperren Sie keine normalen, unfreiwilligen Links innerhalb dieser Elemente.
Trent Walton hatte wahrscheinlich recht vor sechs Jahren
Letztendlich denke ich, dass das Verschwinden von Hover-Zuständen das Web zu einem besseren Ort machen wird. Es gab noch nie einen Ersatz für prägnante Inhalte, klare Interaktion und einfaches Design. Wenn wir uns auf Kernelemente konzentrieren, die das Surfen im Web großartig machen, werden unsere Websites unabhängig davon, wie Menschen sie nutzen, ordnungsgemäß funktionieren.
Demo
Hier ist eines zum Spielen.
Das ist der beste Rat. Wenn Sie schöne Hover-Effekte für Benutzer mit einer Maus bereitstellen möchten, verstecke ich diese Dinge gerne hinter einem
has-touch-Flag mit etwas wie Modernizr.Leider bricht diese Technik auf den meisten modernen Windows-Geräten zusammen, die Touch, Maus und oft auch Stifteingabe kombinieren. Sogar Android-Telefone und -Tablets und iPads unterstützen Maus- und oft auch Stifteingabe. Und Leute mischen oft Eingabemodi – wenn ich einen Stift benutze, scrolle ich oft mit dem Finger. Und ich kann zwischen Maus und Touch wechseln, wenn ich mein Gerät aufhebe, um zu einem Meeting zu gehen.
Ich glaube wirklich nicht, dass es eine „sichere“ Lösung dafür gibt – also stimme ich Ihnen und dem Artikel zu, dass der beste Ansatz darin besteht, Hover-Zustände einfach nicht zum Anzeigen von etwas zu verwenden.
Wie gesagt, leider werden die Media Queries noch nicht weit verbreitet unterstützt.
Was ich derzeit verwende, ist ein winziges JavaScript, bei dem ich auf Touch-Unterstützung und Mausbewegung prüfe, was für mich gut funktioniert. Es ist immer noch nicht perfekt, aber besser als nur auf Touch-Unterstützung zu achten oder sich nur auf Media Queries zu verlassen, die derzeit nicht weit verbreitet sind.
Dieser Codeblock fügt dem HTML-Element die Klassen „touch“ und „mouse“ hinzu, wenn Touch oder eine Maus erkannt wird.
http://codepen.io/anon/pen/JRLmyX
Meiner Meinung nach ist der beste Weg, dies zu handhaben, die Website so zu erstellen, dass sie sich nicht auf „Hover“ verlässt und für Geräte ohne Touch-Fähigkeiten „verbessert“ wird :)
Zum Beispiel könnte Modernizr verwendet werden, um Geräte ohne Touch-Fähigkeiten zu erkennen, was bedeutet
– Standardfall => kein Hover,
– Desktop mit Touch-Fähigkeiten => kein Hover,
– und für alle anderen Fälle => Hover.
Hier ist ein Beispiel auf http://albinism.ohchr.org/
– Standardfall => kein Hover (kein Fade zu Farbe),
– Desktop mit Touch-Fähigkeiten => kein Hover (kein Fade zu Farbe),
– und für alle anderen Fälle => Hover (ok)
Wie auch immer, es ist in der Apple-Dokumentation erklärt: https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html#//apple_ref/doc/uid/TP40006511-SW7
Ich bin vor ein paar Tagen durch dieses spezielle Problem gegangen. Ich hatte ein Bild und etwas Text, die in einem Anker eingeschlossen waren, wenn der Benutzer über das Bild fuhr, wurde der Text über dem Bild angezeigt, ansonsten wurde er mit
display: noneversteckt. Meine Lösung für dieses Problem war, den Text mitopacity: 0zu verstecken undopacity: 1zum Anzeigen des Textes zu verwenden. Wahrscheinlich ist diese Methode nicht für alle Szenarien anwendbar, aber sie kann für einige funktionieren.Ich unterstütze Mauros Kommentar: Diese Doppelklick-Situation tritt nur auf, wenn ein Element innerhalb des Links beim Hovern von
display: noneauf einen anderen Anzeigewert wechselt.Eine einfache Umgehung ist die Verwendung einer anderen Methode zum Verstecken/Anzeigen dieses Elements (opacity, visibility, position...), anstatt
display: none.Auf jeden Fall stimme ich zu, dass diese angezeigten Elemente keine essentiellen sein sollten und die Benutzeroberfläche auch ohne sie verständlich sein sollte, damit Benutzer, die keine Maus verwenden, nicht hilflos bleiben.
Warum ist es jetzt kein so großes Problem mehr? Haben mobile Browser die Verzögerung verkürzt oder eine Umgehung dafür gefunden?
Auf [meiner Website] konnte ich dieses Problem lösen, indem ich anstatt Breite und Höhe verwendete, um ein Pseudoelement innerhalb eines Links zu skalieren,
transform:scale(0);verwendete und dann beim Hovern zutransform:scale(1);wechselte.Dies hat mein Problem teilweise gelöst, da die Animation beginnt, aber iOS sie nicht zulässt, bevor die nächste Seite geladen wird. Also habe ich eine Media Query zu den Schaltflächen hinzugefügt, die
transition:all 0s;einstellt, und interessanterweise funktioniert die Animation unter iOS, obwohl sie kürzer ist, aber sie ist nicht wirklich 0s, sie ist nur kürzer als auf dem Desktop.Ich hoffe, es hilft jemandem, sehen Sie sich den von mir geposteten Link an und inspizieren Sie die Schaltflächen, um zu sehen, was ich meine.
Andreas Deuschlinger schrieb, dass er festgestellt habe, dass
widthdies ebenfalls auslösen kann. Wie beim Einstellen eines Kind-Elements oder Pseudoelements aufwidth: 0, ähnlich wie beidisplay: noneodervisibility: hidden, und dieses „Bug“ auslöst. Ich vermute,height: 0ist ebenfalls ein Problem. Ich wäre neugierig zu sehen, ob das Wegschieben des Elements von der Seite durch absolute Positionierung dasselbe tun würde (ich vermute nicht.)