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


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

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

я был в состоянии заставить вещи работать красиво на 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 90

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 для удаления не трогать класс от тела.

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 чтобы включить как можно меньше или столько обнаружений функций, сколько вам нужно.

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

<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 Surface имеет сенсорный экран, трекпад и стилус, который фактически вызывает события наведения, когда он находится над экраном.

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

это ошибка в 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);

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


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

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

лучшее решение, без каких-либо JS, css class и viewport check: вы можете использовать функции мультимедиа взаимодействия (Медиа Запросы Уровня 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
}