Щелчок в iOS Safari запускает "состояние зависания" на элементе под тем, где вы прослушивали

В iOS Safari (я не думаю, что имеет значение, какая версия iOS, но я тестирую на iOS (Safari) 11), если у меня есть <div>, расположенный над элементом, который имеет эффект :hover, а <div> имеет событие, которое заставляет его исчезать при нажатии, тогда моя ссылка "внизу" получает эффект зависания, применяемый после удаления элемента из DOM.

См. ниже для анимированного GIF того, что я говорю:

iOS click through

Я дал кнопке прозрачный фон, чтобы вы могли видеть ссылку позади нее. Когда я нажимаю кнопку на месте, где находится ссылка не, ссылка (т.е. Some link) остается синей и не меняется на ее кратковременное состояние.

Однако, когда я нажимаю div в месте, которое происходит непосредственно по ссылке, после удаления div из DOM, ссылка получает свое зависающее состояние.

Щелчок по ссылке после каждого из них правильно запускает событие on.click (окно предупреждения).

Я не вижу эту проблему в android в Chrome (см. пример ниже):

Android click through working

Ниже вы также найдете образец HTML/CSS/JS, который я использовал; настройка довольно проста.

Я бы хотел, чтобы iOS действовал так же, как Android Chrome: щелчок по элементу, который сразу же удаляется из DOM, не должен запускать состояние :hover для элемента сразу за ним.

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>

Ответы

Ответ 1

Если у вас есть опция отключения зависания, вы можете сделать это с помощью взлома.

Сначала добавьте эту строку в обработчик событий DOMContentLoaded.

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

Он добавит класс cancan в тело вашего html-документа.

Затем просто измените правило: hover, чтобы соответствовать этому вместо

ваше правило css:

a:hover {
  color: red;
}

должен быть:

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

это должно помешать устройствам с сенсорным экраном применить стиль наведения к любому якорю.

Ответ 2

... можно ясно видеть, что это предполагаемое поведение на iOS, даже если вы просматриваете список элементов, зависящих от наведения.

Если то, что вы пытаетесь избежать, это просто эффект наведения, вот что я буду делать. Я бы получил устройство с помощью JS-функции, применил класс в теге body и удалил любые зависающие эффекты по мере необходимости.

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

Это, по-видимому, неотъемлемое дизайнерское решение в iOS (или, возможно, способ Chrome - это дизайнерское решение, сделанное ими, не может сказать). Кажется, iOS спроектирован так, чтобы быть "мышиным". Он даже бросает "мыши" на веб-страницы даже на сенсорных устройствах. Я пытался найти способ определить, есть ли у пользователя мышь, поэтому вы можете отключить эффекты зависания, если она есть, но я не могу найти ничего, что будет работать правильно.

Я думаю, что Windows делает то же самое с прикосновением. Прикосновение к точке эффективно перемещает указатель мыши и щелкает, оставляя указатель мыши.

Вы можете просто изменить свой дизайн, если это разблокировка сделки.

Ответ 5

Это похоже на намеренное поведение в Safari. Apple documentation говорит, что однодисковые метчики обрабатываются как события мыши и показывают, какие события возникают во время крана. Там mouseover в начале нажатия, но mouseout запускается только при нажатии на что-то еще. Это означает, что Safari предполагает, что указатель остается в одном месте до следующего крана, что будет означать, что нижний элемент имеет смысл в состоянии наведения.

Я пробовал свой код в Chrome на Android, а Chrome и Firefox в Windows (у меня нет устройства Apple). Во всех трех случаях, когда я нажимаю на <div> с помощью мыши (по ссылке), стиль зависания применяется к ссылке позже, если только я не перемещаю курсор от ссылки до того, как я отпущу мышь. Если я коснувшись <div> пальцем на сенсорном экране, ссылка не получит стиль наведения.

Firefox и Chrome, похоже, согласуются друг с другом для сенсорной и мыши, но Safari кажется (по дизайну) рассматривать сенсорный экран как мышь: он ведет себя так же, как для сенсорного нажатия, поскольку Chrome и Firefox делают для щелчок мыши.

Я не это, что это ошибка, которую нужно исправить или обойти. Если вы не знаете, что все ваши пользователи будут использовать определенную комбинацию оборудования/браузера, вам, вероятно, необходимо будет запланировать возможность того, что они могут использовать мышь, сенсорный экран или, возможно, оба одновременно; и разработать пользовательский интерфейс, который работает для всех этих случаев. У моего ноутбука Windows и Android-планшета есть мышиные коврики, а также сенсорные экраны, и я иногда использую мышь USB OTG с моим телефоном Android.

Вы также можете посмотреть API указателей проводок, который работает в Chrome, IE и Edge (не путать с pointer-events Свойство CSS, упомянутое в @erier). Поскольку API имеет дело с событиями, а не с CSS, это не будет напрямую способствовать правильному оформлению вашего стиля, но покажет, как прилагать усилия, чтобы браузеры последовательно реагировали на различные типы устройств ввода.

Ответ 6

Я думаю, что этот хак может работать.

Вам нужно отключить наведение с классом, и когда верхний div щелкнет, добавьте прослушиватель событий, который удалит класс блокировки зависания при перемещении мыши.

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>

Ответ 7

Использование указателей-событий может помочь здесь.

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>

Ответ 8

Я не знаю, будет ли это работать в вашем производственном коде, но это должно быть для этого примера.

Вы можете выплевывать правила наведения на класс и применять этот класс к ссылке в обратном вызове удаления кнопки после того, как вы отменили ее из DOM.

Если это все еще не работает, вы можете добавить класс в обратный вызов onmouseover. Это будет работать только после удаления кнопки и после выхода (если необходимо) и повторного ввода ссылки.

Все это немного взломанно, но это позволит вам использовать поведение в любом браузере/ОС.

Ответ 9

Это проблема с браузерами. состояние зависания существует везде, даже если оно не должно быть.

Я бы добавил класс .no-touch к телу и стилю только те.

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

Здесь все вместе

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>