Чи можна змусити ігнорувати псевдоклас: hover для користувачів iPhone / iPad?


94

На моєму сайті є декілька меню css, які розширюються за допомогою :hover (без js)

Це працює напіврозбито на iDevices, наприклад, натискання активує :hoverправило та розширює меню, але натискання в іншому місці не видаляє :hover. Крім того, якщо в елементі є :hoverпосилання, вам потрібно двічі натиснути, щоб активувати посилання:hover , посилання другого натискання).

Я зміг змусити речі добре працювати на iphone, прив'язавши touchstart подію.

Проблема в тому, що іноді мобільне сафарі все-таки вирішує запускати :hoverправило з css замість могоtouchstart подій!

Я знаю, що це проблема, тому що, коли я відключаю всі :hover правила вручну в css, мобільне сафарі чудово працює (але звичайні браузери, очевидно, цього більше не роблять).

Чи є спосіб динамічно "скасувати" :hoverправила для певних елементів, коли користувач перебуває в мобільному сафарі?

Подивіться і порівняйте поведінку iOS тут: http://jsfiddle.net/74s35/3/ Примітка: лише деякі властивості css ініціюють поведінку у два кліки, наприклад display: none; але не фон: червоний; або оформлення тексту: підкреслення;


7
БУДЬ ЛАСКА, НЕ відключайте наведення лише через наявність подій "дотику". Це негативно вплине на користувачів ноутбуків, які мають сенсорні пристрої та пристрої введення миші. Докладніше див. У моїй відповіді
Simon_Weaver

Відповіді:


77

Я виявив, що ": hover" є непередбачуваним у iPhone / iPad Safari. Іноді натискання на елемент робить цей елемент ": наведення", тоді як іноді він переходить до інших елементів.

На даний момент я просто маю в класі заняття "без дотику".

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

І мати усі правила CSS з ": наведення" внизу ".no-touch":

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

Десь на сторінці у мене є javascript для видалення класу без дотику з тіла.

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

Це не виглядає ідеально, але все одно працює.


5
Це єдиний спосіб зробити це. Мене турбує те, що це забруднює "звичайний" сайт речами, які там не належать і не мають значення. Що ж, добре. Дякую.
Крістофер Кемпс,

Ви також можете використовувати медіа-запити із запасним варіантом для IE
Lime

2
@Shackrock: Я не думаю, що підхід "одним натисканням, щоб навести, а два - клацанням" є хорошим рішенням. Оскільки насправді на сенсорному пристрої немає фактичного наведення (поки вони не мають екранів, які відчувають, як над ним лежить ваш палець), я вважаю, що краще взагалі не імітувати наведення. Для ефектів, таких як загальні для кнопок і посилань, просто пропустіть ефект. Для меню, яке розгортається при наведенні, натомість розширюйте їх натисканням / клацанням. Мій 2c.
Адріан Шмідт,

18
Нещодавно я виявив проблеми з подібним підходом завдяки новим системам Windows 8 із введенням дотику та миші
Том,

4
+1 до коментаря Тома - перевірка наявності ontouchstart поверне істину на ноутбуках із сенсорним екраном, навіть якщо їх підключити до зовнішнього монітора (де веб-сайт, зручний для миші з наведеними станами, є більш бажаним).
gregdev

45

:hoverсправа не в цьому. Safari для iOS дотримується дуже дивного правила. Стріляє mouseoverі mousemoveспочатку; якщо що-небудь змінилося під час цих подій, "клацніть" та пов'язані події не запускаються:

Схема сенсорної події в iOS

mouseenter і mouseleave здається, включені, хоча вони не вказані на діаграмі.

Якщо ви щось змінили в результаті цих подій, події натискання не запускатимуться. Це включає щось вище в дереві DOM. Наприклад, це не дозволить працювати одним натисканням на вашому веб-сайті за допомогою jQuery:

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

Змінити: Для уточнення hoverподія jQuery включає mouseenterта mouseleave. Це обоє запобіжить clickзміні вмісту.


5
звичайно: hover - це проблема :-) або, точніше, баггі-реалізація Safari цього. це цікава довідка щодо цього питання, але Apple - єдина сторона, яка може виправити цю жахливу поведінку. йому або потрібно "розкрити", коли клацнути щось поза елементами, або ніколи не "наводити" в першу чергу. поточна поведінка в основному ламає будь-який веб-сайт, який використовує: наведення курсора на мишку
Simon_Weaver

це допомогло мені зрозуміти, що hoverобробник jquery перешкоджає clickпотраплянню окремого обробника - який жарт!
Simon_Weaver

1
Блискуча відповідь і найкраще пояснення проблеми, з якою я зіткнувся. Проблему "подвійного клацання" викликає не лише наведення CSS, а буквально будь-яка модифікація DOM після подій наведення курсора миші та інших користувачів.
Oliver Joseph Ash

Ось приклад, який показує, що подія натискання не спрацьовує при зміні DOM на mouseenter jsbin.com/maseti/5/edit?html,js,output
Олівер Джозеф Еш,

@Oliver Джозеф Еш Правильно, звідси приклад JS у відповіді. ;)
Zenexer

18

Бібліотека виявлення функцій браузера Modernizer включає перевірку на наявність сенсорних подій.

Типовою поведінкою є застосування класів до елемента 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">

Майте на увазі, що в останніх версіях Chrome на настільних комп’ютерах Modernizr повідомляє про "дотик". Це, мабуть, виправлено у версії 3 за допомогою touchevents.
Крейг Джейкобс,

18

Деякі пристрої (як сказали інші) мають події як на дотик, так і на мишу. Наприклад, у 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 цей тест не пройде і вимкне перекидання.

Найкраща частина такої абстракції полягає в тому, що якщо я виявляю, що вона зламається на певному андроїді або якщо це виправлено в iOS9, я можу просто змінити тест.


Це рішення і неприємне, і найкраще. Він ламається, лише якщо браузер, який бореться з наведенням, має як дотик, так і клацання, але для сенсорних браузерів на ipad / iphone це не так. Моя порада - застосувати це лише як виправлення оптимізації (щоб усунути мерехтіння при наведенні, коли ви вже використовуєте fastclick.js), і переконатися, що все також працює без нього.
Герсом,

Дякую. Я згоден. Цікаво подивитися, що iOS 9 робить для цього випуску - якщо що.
Simon_Weaver

Я пішов у зворотному напрямку:html:not(.no-hover) .category:hover { ...
Кріс Марісіч

+1 для "Safari не" оголошує "світові, що він поводиться погано з: hover" Ця проблема робить iOS набагато гіршою, ніж будь-яка версія IE, на мій погляд ...
Спенсер О'Рейлі

16

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

Просто включіть бібліотеку fastclick.min.js на свою сторінку та активуйте за допомогою:

FastClick.attach(document.body);

Як побічна перевага, це також усуне прикрі 300мс затримки onClick, від яких страждають мобільні пристрої.


Використання FastClick має кілька незначних наслідків, які можуть чи не матимуть значення для вашого сайту:

  1. Якщо натиснути десь на сторінці, прокрутити вгору, прокрутити назад, а потім відпустити палець у тому самому положенні, де ви його розмістили спочатку, FastClick буде інтерпретувати це як "клацання", хоча це, очевидно, ні. Принаймні так це працює у версії FastClick, яку я зараз використовую (1.0.0). Хтось, можливо, вирішив проблему з цієї версії.
  2. FastClick усуває можливість для когось "подвійного клацання".

1
Чи хочете ви поділитися ще одним конкретним прикладом того, як я можу зробити це для свого веб-сайту. Я нічого не знаю про javascript, тому я трохи розгублений щодо того, як це могло б працювати. У мене є всі ці посилання на моєму веб-сайті, над якими користувачі зазвичай наводять курсор перед натисканням, але для ipad / mobile я хочу зробити так, щоб їм не потрібно було натискати двічі.
Енді

@Andy - Не зовсім зрозуміло, що вам потрібно, а що вам не вистачає ... Що ви пробували дотепер і які помилки ви бачите, якщо такі є? Можливо, найкраще створити нове запитання Stackoverflow, якщо ви цього ще не зробили, з прикладом того, що ви намагаєтеся зробити (?) Або спробуйте пояснити, що це у наведеному вище прикладі jsfiddle, чого ви не робите ' я не розумію.
Трой

чи можна це використовувати в односторінкових додатках? Я маю на увазі, коли вміст DOM оновлюється щоразу
Себастьян Лорбер,

Так, я використовую його з односторінковими додатками.
Трой

16

Краще рішення, без будь-якого JS, класу css та перевірки області перегляду: ви можете використовувати функції взаємодії мультимедіа (медіа-запити рівень 4)

Подобається це:

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

iOS Safari підтримує це

Докладніше про: https://www.jonathanfielding.com/an-introduction-to-interaction-media-features/


Не підтримується Firefox (на момент
Френк

Тепер це підтримує і Firefox (FF 64+, випущений в грудні 2018 р.).
забій

4

В основному існує три сценарії:

  1. Користувач має лише пристрій миші / вказівника і може активувати:hover
  2. Користувач тільки має сенсорний екран, і не може активувати :hoverелементи
  3. Користувач має як сенсорний екран, так і вказівник

Спочатку прийнята відповідь чудово працює, якщо можливі лише перші два сценарії, коли користувач має або вказівник, або сенсорний екран. Це було поширеним явищем, коли ОП задало питання 4 роки тому. Кілька користувачів зазначили, що пристрої Windows 8 і Surface роблять третій сценарій більш імовірним.

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

На даний момент найбезпечнішим рішенням є уникнення використання :hoverяк єдиного способу взаємодії користувача з вашим веб-сайтом. Ефекти наведення - це хороший спосіб вказати, що посилання чи кнопка діє, але користувач не повинен вимагати наведення елемента для виконання дії на вашому веб-сайті.

Переосмислення функціональності “наведення” з урахуванням сенсорних екранів добре обговорює альтернативні підходи UX. Рішення, передбачені відповіддю, включають:

  • Заміна меню наведення на прямі дії (завжди видимі посилання)
  • Заміна меню наведення при наведенні на меню, яке можна натиснути
  • Переміщення великої кількості вмісту під час наведення на окрему сторінку

Просуваючись вперед, це, мабуть, буде найкращим рішенням для всіх нових проектів. Прийнята відповідь, мабуть, друге найкраще рішення, але обов’язково враховуйте пристрої, які також мають вказівні пристрої. Будьте обережні, щоб не усунути функціональність, коли пристрій має сенсорний екран лише для того, щоб обійти :hoverхакерство iOS .


1

Версія JQuery у вашому .css використовує .no-touch .my-element: hover для всіх ваших правил наведення, включає JQuery та наступний сценарій

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

Потім у тег body додати class = "no-touch" ontouchstart = "removeHoverState ()"

як тільки стартовий запуск запускає клас для всіх станів наведення, видаляється


0

Замість того, щоб мати ефект наведення лише тоді, коли дотик недоступний, я створив систему для обробки сенсорних подій, яка вирішила проблему для мене. По-перше, я визначив об’єкт для тестування на події "натискання" (еквівалентно "клацанню").

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.
            });

0

Завдяки @Morgan Cheng за відповідь, але я трохи змінив функцію JS для отримання « touchstart » (код взятий з @Timothy Perez відповіді ), хоча, вам потрібно JQuery 1.7+ для цього

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

0

З огляду на відповідь, надану 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
    }
});

Цей метод запускає наведення миші першим, клацання другим.


0

Я згоден з тим, що вимкнути наведення курсора на дотик - це шлях.

Однак, щоб уберегти себе від перезапису вашого css, просто оберніть будь-які :hoverелементи @supports not (-webkit-overflow-scrolling: touch) {}

.hover, .hover-iOS {
  display:inline-block;
  font-family:arial;
  background:red;
  color:white;
  padding:5px;
}
.hover:hover {
  cursor:pointer;
  background:green;
}

.hover-iOS {
  background:grey;
}

@supports not (-webkit-overflow-scrolling: touch) {
  .hover-iOS:hover {
    cursor:pointer;
    background:blue;
  }

}
<input type="text" class="hover" placeholder="Hover over me" />

<input type="text" class="hover-iOS" placeholder="Hover over me (iOS)" />


0

Для тих, хто зазвичай використовує вимкнення :hoverподій у iOS Safari, найпростіший спосіб - використовувати медіа-запит мінімальної ширини для ваших :hoverподій, який залишається вище ширини екрана пристроїв, яких ви уникаєте. Приклад:

@media only screen and (min-width: 1024px) {
  .my-div:hover { // will only work on devices larger than iOS touch-enabled devices. Will still work on touch-enabled PCs etc.
    background-color: red;
  }
}

-6

Просто подивіться на розмір екрану ....

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

-12

ось код, в який ви хочете його розмістити

// 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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.