Отключить эффекты наведения на мобильные браузеры - PullRequest
110 голосов
/ 28 ноября 2011

Я пишу веб-сайт, предназначенный для использования как с настольных компьютеров, так и с планшетов. Когда его посещают с рабочего стола, я хочу, чтобы области экрана, на которые можно нажимать, подсвечивались эффектами :hover (другой цвет фона и т. Д.). На планшете нет мыши, поэтому я не хочу никаких эффектов наведения мыши.

Проблема в том, что когда я нажимаю что-то на планшете, браузер, очевидно, имеет какой-то «невидимый курсор мыши», который перемещается в место, которое я коснулся, и затем оставляет его там - так что вещь, которую я только что нажал, горит с эффектом парения, пока я не коснусь чего-то другого.

Как получить эффекты наведения при использовании мыши, но подавить их при использовании сенсорного экрана?

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

Я уже пытался перехватить события touchstart, touchmove и touchend и вызвать preventDefault() для всех из них, что иногда подавляет «невидимый курсор мыши»; но если я быстро нажму вперед и назад между двумя различными элементами, после нескольких нажатий он начнет перемещать «курсор мыши» и, в любом случае, подсвечивать эффекты наведения - это как будто мой preventDefault не всегда соблюдается. Я не буду утомлять вас деталями без необходимости - я даже не уверен, что это правильный подход; если у кого-то есть более простое решение, я весь в ушах.


Редактировать: Это может быть воспроизведено с помощью стандартного болотного CSS :hover, но вот краткое повторение для справки.

<style>
  .box { border: 1px solid black; width: 150px; height: 150px; }
  .box:hover { background: blue; }
</style>
<div class="box"></div>
<div class="box"></div>

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

Я также опубликовал пример здесь , который выполняет вышеприведенное, а также перехватывает события мыши jQuery. Вы можете использовать его, чтобы увидеть, что события касания также будут запускать mouseenter, mousemove и mouseleave.

Ответы [ 17 ]

0 голосов
/ 12 апреля 2017

Здравствуйте, человек из будущего, вы, вероятно, хотите использовать медиа-запрос pointer и / или hover. Медиа-запрос handheld устарел.

/* device is using a mouse or similar */
@media (pointer: fine) {
  a:hover {
    background: red;
  }
}
0 голосов
/ 24 февраля 2016

Включите Modernizr на своей странице и установите вместо этого следующие состояния наведения:

html.no-touchevents .box:hover {
    background: blue;
}
0 голосов
/ 11 июля 2013

В проекте, который я недавно делал, я решил эту проблему с помощью функции делегированных событий jQuery.Он ищет определенные элементы, используя селектор jQuery, и добавляет / удаляет класс CSS для этих элементов, когда мышь находится над элементом.Кажется, он работает хорошо, насколько мне удалось его протестировать, включая IE10 на сенсорном ноутбуке под управлением Windows 8.

$(document).ready(
    function()
    {
        // insert your own selector here: maybe '.hoverable'?
        var selector = 'button, .hotspot';

        $('body')
            .on('mouseover', selector, function(){ $(this).addClass('mouseover');    })
            .on('mouseout',  selector, function(){ $(this).removeClass('mouseover'); })
            .on('click',     selector, function(){ $(this).removeClass('mouseover'); });
    }
);

edit: Это решение, конечно же, требует, чтобы вы изменили свой CSS, чтобы удалить селекторы ": hover", и заранее обдумайте, какие элементы вы хотите быть "перемещаемыми".

Если у вас оченьоднако для многих элементов на вашей странице (например, нескольких тысяч) он может работать немного медленнее, поскольку это решение отлавливает события трех типов на всех элементах на странице, а затем выполняет свою функцию, если селектор совпадает.Я назвал CSS-класс «mouseover» вместо «hover», потому что не хотел, чтобы читатели CSS читали «: hover», где я написал «.hover».

0 голосов
/ 12 сентября 2012

Если вы счастливы использовать JavaScript, тогда вы можете использовать Modernizr на своей странице.Когда страница загружается, в браузер без сенсорного экрана будет добавлен класс «.no-touch» к тегу html, но для браузера с сенсорным экраном тег html будет иметь класс «.touch», добавленный к тегу html.,

Тогда нужно просто проверить, имеет ли тег html класс no-touch, прежде чем принять решение о добавлении слушателей mouseenter и mouseleave.

if($('html').hasClass('no-touch')){
    $('.box').on("mouseenter", function(event){
            $(this).css('background-color','#0000ff')
    });
    $('.box').on("mouseleave", function(event){
            $(this).css('background-color','')
    });
}

Для устройства с сенсорным экраному событий не будет прослушивателей, поэтому при нажатии вы не получите эффекта наведения.

0 голосов
/ 07 августа 2014

Вот мое решение: http://jsfiddle.net/agamemnus/g56aw709/-- код ниже.

Все, что нужно сделать, это преобразовать их ": hover" в ".hover" ... вот и все! Большая разница между этим и остальным заключается в том, что это также будет работать с неособыми селекторами элементов, такими как .my_class > *:hover {.

handle_css_hover_effects ()

function handle_css_hover_effects (init) {
 var init = init || {}
 var handle_touch_events = init.handle_touch_events || true
 var handle_mouse_events = init.handle_mouse_events || true
 var hover_class         = init.hover_class         || "hover"
 var delay_preferences   = init.delay_preferences   || {touch: {add: 500, remove: 500}}
 function default_handler (curobj, input_type, op) {
  var hovered_element_selector = "*" + ((op == "add") ? ":" : ("." + hover_class))
  var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll(hovered_element_selector))
  var modified_list = []
  while (true) {
   if ((curobj == null) || (curobj == document.documentElement)) break
   if (hovered_elements.indexOf(curobj) != -1) modified_list.push (curobj)
   curobj = curobj.parentNode
  }
  function do_hover_change () {modified_list.forEach (function (curobj) {curobj.classList[op](hover_class)})}
  if ((!delay_preferences[input_type]) || (!delay_preferences[input_type][op])) {
   do_hover_change ()
  } else {
   setTimeout (do_hover_change, delay_preferences[input_type][op])
  }
 }

 if (handle_mouse_events) {
  document.body.addEventListener ('mouseover' , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "add")})
  document.body.addEventListener ('mouseout'  , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
  document.body.addEventListener ('click'     , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
 }

 if (handle_touch_events) {
  document.body.addEventListener ('touchstart', function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "add")})
  document.body.addEventListener ('touchend'  , function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "remove")})
  document.body.addEventListener ('touchmove',  function (evt) {
   var curobj = evt.target
   var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll("*:hover"))
   var lastobj = null
   evt = evt.changedTouches[0]
   var elements_at_point = get_elements_at_point (evt.pageX, evt.pageY)
   // Get the last element that isn't at the current point but is still hovered over, and remove only its hover attribute.
   while (true) {
    if ((curobj == null) || (curobj == document.documentElement)) break
    if ((hovered_elements.indexOf(curobj) != -1) && (elements_at_point.indexOf(curobj) == -1)) lastobj = curobj
    curobj = curobj.parentNode
   }
   if (lastobj == null) return
   if ((!delay_preferences.touch) || (!delay_preferences.touch.remove)) {
    lastobj.classList.remove(hover_class)
   } else {
    setTimeout (function () {lastobj.classList.remove(hover_class)}, delay_preferences.touch.remove)
   }

   function get_elements_at_point (x, y) {
    var el_list = [], pe_list = []
    while (true) {
     var curobj = document.elementFromPoint(x, y)
     if ((curobj == null) || (curobj == document.documentElement)) break
     el_list.push (curobj); pe_list.push (curobj.style.pointerEvents)
     curobj.style.pointerEvents = "none"
    }
    el_list.forEach (function (current_element, i) {current_element.style.pointerEvents = pe_list[i]})
    return el_list
   }
  })
 }
}
0 голосов
/ 11 января 2019

Попробуйте это простое решение jquery 2019 года, хотя оно уже давно;

  1. добавьте этот плагин в голову:

    src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"

  2. добавить это к js:

    $("*").on("touchend", function(e) { $(this).focus(); }); //applies to all elements

  3. некоторые предлагаемые варианты этого:

    $(":input, :checkbox,").on("touchend", function(e) {(this).focus);}); //specify elements
    
    $("*").on("click, touchend", function(e) { $(this).focus(); });  //include click event`
    
    css: body { cursor: pointer; } //touch anywhere to end a focus`
    

Примечания

  • Поместите плагин перед bootstrap.js, если применимо, чтобы избежать влияния на всплывающие подсказки
  • , протестированные только на iphone XR ios 12.1.12 и ipad 3 ios 9.3.5, используя Safari или Chrome.

Ссылки:

https://code.jquery.com/ui/

https://api.jquery.com/category/selectors/jquery-selector-extensions/

0 голосов
/ 28 ноября 2011

Это может помочь увидеть ваш CSS, так как это звучит довольно странно. Но в любом случае, если это происходит и все остальное хорошо, вы можете попробовать перенести эффект наведения на javascript (вы также можете использовать jquery). Просто привяжите к событию mouseover или, что еще лучше, mouseenter и осветите свой элемент при возникновении события.

Ознакомьтесь с последним примером здесь: http://api.jquery.com/mouseover/, вы можете использовать что-то похожее, чтобы регистрировать, когда событие запускается, и взять его оттуда!

...