web-dev-qa-db-de.com

Ein Klick in iOS Safari löst einen "Hover-Status" auf dem Element unterhalb des Berührungsbereichs aus

Unter iOS Safari (Ich glaube nicht, welche Version von iOS von Bedeutung ist, aber ich teste auf iOS (Safari) 11), wenn ein <div> über einem Element positioniert ist, das einen :hover-Effekt hat. und der <div> hat ein Ereignis, durch das das Fenster verschwunden ist, wenn darauf geklickt wird. Dann erhält mein Link "darunter" den Hover-Effekt, nachdem das Element aus dem DOM entfernt wurde.

Unten finden Sie eine animierte GIF von dem, worüber ich spreche:

 iOS click through

Ich habe dem Button einen durchsichtigen Hintergrund gegeben, damit Sie den Link dahinter sehen können. Wenn ich die Schaltfläche an einer Stelle anklicke, an der sich der Link nicht befindet, bleibt der Link (d. H. Some link) blau und wechselt nicht in den Schwebeflugzustand Rot.

Wenn ich jedoch auf div an einer Stelle tippe, die zufällig direkt über der Link ist, nachdem der div aus dem DOM entfernt wurde, erhält der Link seinen Hover-Status.

Wenn Sie nach jedem dieser Links auf den Link klicken, wird dessen on.click-Ereignis (ein Alarmfenster) ausgelöst.

Ich nicht sehe dieses Problem unter Android in Chrome (siehe Beispiel unten):

 Android click through working

Nachfolgend finden Sie auch das von mir verwendete Beispiel HTML/CSS/JS. Das Setup ist ziemlich einfach.

Ich möchte, dass iOS auf dieselbe Weise wie Android Chrome agiert: Klicken Sie auf ein Element, das sofort aus dem DOM sollte nicht entfernt wird, und lösen Sie einen :hover-Status für ein unmittelbar dahinter liegendes Element aus.

document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function() {
    button.parentNode.removeChild(button);
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a:link    { color: blue }
a:visited { color: blue }
a:hover   { color: red }
a:active  { color: green }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
<a href="#">Some link</a>
<div class="button">Click me!</div>

16
romellem

Wenn Sie die Möglichkeit haben, den Hover zu deaktivieren, können Sie dies mit etwas Hack tun.

Fügen Sie diese Zeile zuerst in der Ereignisbehandlungsroutine "DOMContentLoaded" hinzu.

var canHover = !(matchMedia('(hover: none)').matches);
if (canHover) {
  document.body.classList.add('can-hover');
}

Es wird die .can-hover-Klasse zum Hauptteil Ihres HTML-Dokuments hinzufügen.

Dann bearbeiten Sie einfach eine: hover-Regel, um diese anzupassen

ihre CSS-Regel:

a:hover {
  color: red;
}

sollte sein:

.can-hover a:hover {
  color: red;
}

dies sollte verhindern, dass Geräte mit Touchscreen einen Hover-Stil auf einen Anker anwenden.

6
Milan Jaric

Haben Sie versucht, eine Medienabfrage zu verwenden, um Folgendes zu testen: Hover-Funktion?

Siehe https://drafts.csswg.org/mediaqueries/#hover

4
Josh Palmeri

... Es ist deutlich zu erkennen, dass dies das beabsichtigte Verhalten von iOS ist, selbst wenn Sie eine Liste von schwebefähigen Elementen durchziehen.

Wenn das, was Sie vermeiden möchten, nur der Hover-Effekt ist, würde ich Folgendes tun. Ich würde das Gerät mit einer JS-Funktion erhalten, eine Klasse auf den Tag body anwenden und nach Bedarf Hover-Effekte entfernen.

Javascript:

function isAppleDevice() {
  return (
    (navigator.userAgent.toLowerCase().indexOf("ipad") > -1) ||
    (navigator.userAgent.toLowerCase().indexOf("iphone") > -1) ||
    (navigator.userAgent.toLowerCase().indexOf("iPod") > -1)
   );
}
if (isAppleDevice() {
  $('body').addClass('is_Apple')
}

CSS:

.is_Apple a:hover {
  // same styling as not hovering
}
4
scooterlord

Dies scheint eine inhärente Designentscheidung in iOS zu sein (oder vielleicht ist die Chrome-Methode die von ihnen getroffene Designentscheidung; ich kann es nicht sagen). Es scheint, als sei iOS so konzipiert, dass es "mausähnlich" ist. Sogar "Mouseovers" auf Webseiten werden sogar auf ihren Touch-Only-Geräten ausgelöst. Ich habe versucht, herauszufinden, ob der Benutzer über eine Maus verfügt, sodass Sie die Hover-Effekte deaktivieren können, falls vorhanden, aber ich kann nichts finden, das ordnungsgemäß funktioniert.

Ich denke, Windows macht dasselbe auch mit Berührung. Durch Berühren eines Punkts wird der Mauszeiger effektiv dorthin bewegt und klickt. Der Mauszeiger bleibt dabei.

Sie müssen möglicherweise nur Ihr Design ändern, wenn dies ein Deal-Breaker ist.

1
Joseph Hansen

Dies scheint das beabsichtigte Verhalten in Safari zu sein. Apples documentation gibt an, dass Ein-Finger-Taps als Maus-Events behandelt werden und zeigt, welche Events während eines Taps ausgelöst werden. Es gibt eine mouseover am Anfang des Taps, aber eine mouseout wird nur ausgelöst, wenn Sie auf etwas anderes klicken. Dies impliziert, dass Safari davon ausgeht, dass der Zeiger bis zum nächsten Tippen an der gleichen Stelle bleibt. Dies würde bedeuten, dass es für das untere Element sinnvoll ist, sich im Hover-Status zu befinden.

Ich habe Ihren Code in Chrome unter Android und Chrome und Firefox unter Windows ausprobiert (ich habe kein Apple-Gerät). In allen drei Fällen, wenn ich mit der Maus (über dem Link) auf <div> klicke, wird der Hover-Stil anschließend auf den Link angewendet, es sei denn, ich bewege den Cursor vom Link weg, bevor ich die Maustaste loslasse. Wenn ich mit dem Finger auf dem <div> auf dem Touchscreen tippe, erhält der Link nicht den Hover-Stil.

Firefox und Chrome scheinen bei Berührung und Maus miteinander konsistent zu sein, aber Safari scheint den Touchscreen (vom Design) wie eine Maus zu behandeln: Er verhält sich bei einer Berührung ähnlich wie Chrome & Firefox für einen Mausklick.

Ich kann nicht sagen, dass dies ein Fehler ist, den Sie reparieren oder umgehen müssen. Wenn Sie nicht wissen, dass alle Benutzer eine bestimmte Hardware-/Browserkombination verwenden, müssen Sie wahrscheinlich planen, dass sie möglicherweise eine Maus, einen Touchscreen oder möglicherweise beides gleichzeitig verwenden. und eine Benutzeroberfläche entwerfen, die für alle diese Fälle funktioniert. Mein Windows-Laptop und mein Android-Tablet verfügen über Mauspads und Touchscreens. Manchmal verwende ich eine USB-OTG-Maus mit meinem Android-Handy.

Sie können sich auch die Pointer Events-API anschauen, die in Chrome, IE und Edge funktioniert (nicht zu verwechseln mit der von @erier genannten pointer-events -Eigenschaft). Da sich die API nicht mit CSS, sondern mit Ereignissen befasst, hilft dies nicht direkt beim richtigen Styling, sondern zeigt die Bemühungen, dass Browser konsequent auf verschiedene Arten von Eingabegeräten reagieren.

1
JRI

Ich hatte ein ähnliches Problem, das ich durch das Hinzufügen von Zeigerereignissen für einen Sekundenbruchteil kurz vor dem Entfernen des Elements gelöst und dann wieder zurückgesetzt habe, nachdem es verschwunden ist.

document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function() {
    document.querySelector('a').classList.add("no-click");
    button.parentNode.removeChild(button);
    setTimeout(function() {
        document.querySelector('a').classList.remove("no-click");
    },1);
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a:link    { color: blue }
a:visited { color: blue }
a:hover   { color: red }
a:active  { color: green }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
.no-click {
    pointer-events: none;
}
<a href="#">Some link</a>
<div class="button">Click me!</div>

1
marmite

Ich weiß nicht, ob dies in Ihrem Produktionscode funktionieren würde, aber es sollte für dieses Beispiel gelten. 

Sie können Ihre Hover-Regeln für eine Klasse ausspucken und diese Klasse auf den Link in Ihrem Callback zum Entfernen der Schaltfläche anwenden, nachdem Sie sie aus dem DOM übernommen haben.

Wenn das immer noch nicht funktioniert, können Sie die Klasse in einem onmouseover-Callback hinzufügen. Dies funktioniert nur, nachdem die Schaltfläche entfernt wurde und nachdem der Link (falls relevant) beendet und erneut eingegeben wurde.

Es ist alles ein bisschen hackig, aber es würde Ihnen erlauben, das Verhalten an jeden Browser/OS anzupassen.

0
allnodcoms

Ich denke, dieser Hack kann funktionieren.

Sie müssen den Hover mit einer Klasse deaktivieren. Wenn das oberste Div angeklickt wurde, fügen Sie einen Ereignis-Listener hinzu, der die Hover-Blocking-Klasse bei der Mausbewegung entfernt.

document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function() {
    button.parentNode.removeChild(button);
    var body = document.querySelector("body");
    body.addEventListener("mousemove", function() {
            var someLink = document.querySelector(".some-link");
            someLink.classList.remove("no-hover");
        });
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a:link    { color: blue }
a:visited { color: blue }
a:hover   { color: red }
a:active  { color: green }

a.no-hover:hover { color: blue }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
<a href="#" class="some-link no-hover">Some link</a>
<div class="button">Click me!</div>

0
Joseph Hansen

Hier kann die Verwendung von Zeigerereignissen hilfreich sein.

document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function() {
    button.parentNode.removeChild(button);
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a {pointer-events: none;}
a:link    { color: blue; pointer-events: auto; }
a:visited { color: blue }
a:hover   { color: red; pointer-events: auto; }
a:active  { color: green; pointer-events: auto; }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
<a href="#">Some link</a>
<div class="button">Click me!</div>

0
erier

Testen Sie mit der neuen Medienabfragemethode, ob der primäre Eingabemechanismus des Benutzers über Elemente schweben kann.

@media (hover) {
  // Your hover effects
  a:hover {
    color: red;
  }
}

Docs: Hover - CSS: Cascading Style Sheets | MDN

0
HarryMoore

Dies ist ein Problem mit Browsern. Schwebezustand existiert überall, auch wenn es nicht sein sollte.

Ich würde eine Klasse von .no-touch zum Körper und Stil hinzufügen, nur die.

if (!("ontouchstart" in document.documentElement)) {
    document.body.classList.add('no-touch')
}

Hier ist alles zusammen

if (!("ontouchstart" in document.documentElement)) {
    document.body.classList.add('no-touch')
}
document.addEventListener("DOMContentLoaded", function ready() {
  var button = document.querySelector(".button");
  button.addEventListener("click", function(e) {
    button.parentNode.removeChild(button);
  });
  
  document.querySelector('a').addEventListener("click", function() {
    window.alert('clicked!');
  });
});
a:link    { color: blue }
a:visited { color: blue }
.no-touch a:hover   { color: red }
a:active  { color: green }

.button {
    background: rgba(100, 0, 0, .4);
    position: absolute;
  
    top: 2px;
    left: 2px;
    z-index: 1;

    width: 100px;
    height: 100px;
    line-height: 100px;

    text-align: center;
    border-radius: 5px;
}

.button:hover {
    background: rgba(0, 100, 0, .4);
    cursor: pointer;
}
<a href="#">Some link</a>
<div class="button">Click me!</div>

Ich weiß, dass dies möglicherweise nicht die Antwort ist, die Sie suchen, aber es wird definitiv die Konsistenz zwischen Android und iOS beibehalten. Hilft möglicherweise anderen mit dem gleichen Problem in der Zukunft.

0
Joao Lopes