Можно ли заставить игнорировать: hover псевдокласс для пользователей iPhone / iPad?

у меня есть некоторые меню css на моем сайте, которые расширяются с :hover (без js)

это работает в полу-сломанном пути на iDevices, например кран активирует :hover правило и развернуть меню, но затем нажав в другом месте не удаляет :hover. Также если есть ссылки внутри элемента :hover'ed, вы должны нажать дважды, чтобы активировать ссылку (первый кран триггеры :hover, второе нажатие вызывает ссылку).

я смог заставить вещи работать красиво на iphone, связав touchstart событие.

проблема в том, что иногда mobile safari по-прежнему выбирает для запуска :hover правило из css вместо моего touchstart событий!

Я знаю, что это проблема, потому что, когда я отключить все :hover правила вручную в css, mobile safari отлично работает (но обычные браузеры, очевидно, больше не работают).

есть ли способ динамически "отменить":hover правила для определенных элементов когда пользователь находится на мобильном safari?

см. и сравните поведение iOS здесь:http://jsfiddle.net/74s35/3/ Примечание. только некоторые свойства css запускают поведение с двумя щелчками мыши, например display: none; но не background: red; или text-decoration: underline;

13 ответов


я обнаружил, что": hover " непредсказуем в iPhone/iPad Safari. Иногда нажмите на элемент, чтобы сделать этот элемент": hover", а иногда он дрейфует к другим элементам.

на данный момент у меня просто есть класс" без прикосновения " в body.

<body class="yui3-skin-sam no-touch">
   ...
</body>

и имеют все правила CSS с": hover " ниже ".no-touch":

.no-touch my:hover{
   color: red;
}

где-то на странице у меня есть javascript для удаления нет-touch класс от тела.

if ('ontouchstart' in document) {
    Y.one('body').removeClass('no-touch');
}

Это не выглядит отлично, но все равно работает.


:hover здесь не проблема. Safari для iOS следует очень странному правилу. Он стреляет mouseover и mousemove во-первых; если что-то изменилось во время этих событий, "нажмите" и связанные события не будут уволены:

mouseenter и mouseleave по-видимому, включены, хотя они не указаны в диаграмме.

если вы измените что-либо в результате этих событий, нажмите события не будут уволены. Это включает что-то более высокое в дерево DOM. Например, это предотвратит работу одиночных кликов на вашем сайте с помощью jQuery:

$(window).on('mousemove', function() {
    $('body').attr('rel', Math.random());
});

Edit: для уточнения, jQuery hover событие включает в себя mouseenter и mouseleave. Они оба предотвратят click если контент меняется.


библиотека обнаружения функций браузера модернизатор включает в себя проверку сенсорных событий.

это поведение по умолчанию заключается в применении классов к вашему html-элементу для каждой обнаруживаемой функции. Затем эти классы можно использовать для создания стиля документа.

если события касания не включены, Modernizr может добавить класс no-touch:

<html class="no-touch">

а затем область ваших стилей наведения с этим классом:

.no-touch a:hover { /* hover styles here */ }

вы можете скачать пользовательский Modernizr build включить некоторые или многие функции, так как вам нужно.

вот пример некоторых классов, которые могут быть применены:

<html class="js no-touch postmessage history multiplebgs
             boxshadow opacity cssanimations csscolumns cssgradients
             csstransforms csstransitions fontface localstorage sessionstorage
             svg inlinesvg no-blobbuilder blob bloburls download formdata">

некоторые устройства (как говорили другие) имеют события касания и мыши. Например, поверхность Microsoft имеет сенсорный экран, трекпад и стилус, который фактически вызывает события наведения, когда он завис над экраном.

любое решение, которое отключает :hover на основе наличия событий "touch" также повлияет на пользователей Surface (и многие другие подобные устройства). Многие новые ноутбуки touch и будут реагировать на сенсорные события - поэтому отключение зависания действительно плохо практиковать.

это ошибка в Safari, нет абсолютно никакого оправдания для этого ужасного поведения. Я отказываюсь саботировать не iOS браузеры из-за ошибки в iOS Safari, которая, по-видимому, была там в течение многих лет. Я действительно надеюсь, что они исправят это для iOS8 на следующей неделе, но пока....

мое решение:

некоторые предложили использовать Modernizr уже, Ну Modernizr позволяет создавать свои собственные тесты. То, что я здесь делаю, это "абстрагирование" идея браузера, который поддерживает :hover в тест Modernizr, который я могу использовать во всем своем коде без жесткого кодирования if (iOS) на протяжении.

 Modernizr.addTest('workinghover', function ()
 {
      // Safari doesn't 'announce' to the world that it behaves badly with :hover
      // so we have to check the userAgent  
      return navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? false : true;
 });

тогда css становится чем-то вроде этого

html.workinghover .rollover:hover 
{
    // rollover css
}

только на iOS этот тест завершится неудачей и отключит опрокидывание.

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


добавлять библиотека FastClick на вашу страницу приведет к тому, что все краны на мобильном устройстве будут превращены в события щелчка (независимо от того, где пользователь нажимает), поэтому он также должен исправить проблему наведения на мобильных устройствах. Я отредактировал вашу скрипку в качестве примера:http://jsfiddle.net/FvACN/8/.

просто включите fastclick.минута.JS lib на Вашей странице, и активировать через:

FastClick.attach(document.body);

в качестве побочного преимущества он также удалит раздражающий 300ms onClick задержка, от которой страдают мобильные устройства.


Есть несколько незначительных последствий использования FastClick, которые могут иметь или не иметь значения для вашего сайта:

  1. если вы нажмете где-нибудь на странице, прокрутите вверх, прокрутите вниз, а затем отпустите палец в том же положении, в котором вы его изначально разместили, FastClick будет интерпретировать это как "щелчок", хотя это, очевидно, не так. По крайней мере, так это работает в версии FastClick, которую я сейчас используя (1.0.0). Кто-то, возможно, исправил проблему с этой версии.
  2. FastClick удаляет возможность для кого-то"двойной щелчок".

лучшее решение, без каких-либо JS, css class и viewport check: вы можете использовать функции Interaction Media (Медиа-Запросы Уровня 4)

такой:

@media (hover) {
  // properties
  my:hover {
    color: red;
  }
}

iOS Safari поддерживает

подробнее о: https://www.jonathanfielding.com/an-introduction-to-interaction-media-features/


есть в основном три варианта:

  1. пользователей только имеет устройство мыши / указателя и может активировать :hover
  2. пользователей только имеет сенсорный экран, и не смогут активировать :hover элементов
  3. пользователь и сенсорный экран и указатель прибора

первоначально принятый ответ Отлично работает, если возможны только первые два сценария, где пользователь имеет или указатель или сенсорный экран. Это было распространено, когда ОП задал вопрос 4 года назад. Несколько пользователей отметили, что устройства Windows 8 и Surface делают третий сценарий более вероятным.

решение iOS для проблемы невозможности зависания на сенсорных устройствах (как подробно описано @Zenexer) является умным, но может привести к неправильному поведению простого кода (как отмечено OP). Отключение наведения только для сенсорных устройств означает, что вам все равно нужно будет закодировать сенсорный экран чистая альтернатива. Обнаружение, когда у пользователя есть указатель и сенсорный экран, еще больше мутит воду (как объяснил @Simon_Weaver).

на данный момент самое безопасное решение-избегать использования :hover как единственный способ взаимодействия пользователя с вашим сайтом. Эффекты наведения-хороший способ указать, что ссылка или кнопка применимы, но пользователю не нужно наводить элемент для выполнения действия на вашем веб-сайте.

переосмысление " hover" функциональность с сенсорными экранами в виду имеет хорошее обсуждение альтернативных подходов UX. Решения ответ туда входит:

  • замена меню наведения на прямые действия (всегда видимые ссылки)
  • замена меню при наведении курсора на меню при нажатии
  • перемещение большого количества содержимого при наведении на отдельную страницу

двигаясь вперед, это, вероятно, будет лучшим решением для всех новых проектов. Этот принятый ответ, вероятно, является вторым лучшим решением, но обязательно учитывайте устройства, которые также имеют устройства указателей. Будьте осторожны, чтобы не исключить функциональность, когда устройство имеет сенсорный экран только для работы вокруг iOS :hover рубить.


версия JQuery в твоем .использование css .нет-сенсорный .мой-элемент:Ховер для всех правил Ховер включите JQuery и следующий скрипт

function removeHoverState(){
    $("body").removeClass("no-touch");
}

затем в теге body добавить class= "no-touch" ontouchstart= " removeHoverState ()"

Как только ontouchstart запускает класс для всех состояний наведения, удаляется


вместо того, чтобы только эффекты наведения, когда прикосновение недоступно, я создал систему для обработки событий касания, и это решило проблему для меня. Во-первых, я определил объект для тестирования событий "tap" (эквивалент "click").

touchTester = 
{
    touchStarted: false
   ,moveLimit:    5
   ,moveCount:    null
   ,isSupported:  'ontouchend' in document

   ,isTap: function(event)
   {
      if (!this.isSupported) {
         return true;
      }

      switch (event.originalEvent.type) {
         case 'touchstart':
            this.touchStarted = true;
            this.moveCount    = 0;
            return false;
         case 'touchmove':
            this.moveCount++;
            this.touchStarted = (this.moveCount <= this.moveLimit);
            return false;
         case 'touchend':
            var isTap         = this.touchStarted;
            this.touchStarted = false;
            return isTap;
         default:
            return true;
      }
   }
};

затем в моем обработчике событий я делаю что-то вроде следующего:

$('#nav').on('click touchstart touchmove touchend', 'ul > li > a'
            ,function handleClick(event) {
               if (!touchTester.isTap(event)) {
                  return true;
               }

               // touch was click or touch equivalent
               // nromal handling goes here.
            });

спасибо @Morgan Cheng за ответ, однако я немного изменил функцию JS для получения"touchstart" (код взят из @Timothy Perez ответ), однако, вам нужен jQuery 1.7+ для этого

  $(document).on({ 'touchstart' : function(){
      //do whatever you want here
    } });

учитывая ответ, предоставленный Zenexer, шаблон, который не требует дополнительных тегов HTML:

jQuery('a').on('mouseover', function(event) {
    event.preventDefault();
    // Show and hide your drop down nav or other elem
});
jQuery('a').on('click', function(event) {
    if (jQuery(event.target).children('.dropdown').is(':visible') {
        // Hide your dropdown nav here to unstick
    }
});

этот метод сначала запускает наведение мыши, затем щелчок.


просто посмотрите на размер экрана....

@media (min-width: 550px) {
    .menu ul li:hover > ul {
    display: block;
}
}

вот код, который вы хотите поместить в

// a function to parse the user agent string; useful for 
// detecting lots of browsers, not just the iPad.
function checkUserAgent(vs) {
    var pattern = new RegExp(vs, 'i');
    return !!pattern.test(navigator.userAgent);
}
if ( checkUserAgent('iPad') ) {
    // iPad specific stuff here
}