Как предотвратить эффект зависания кнопок на сенсорных устройствах

Я создал карусель с предыдущей и следующей кнопками, которые всегда видны. Эти кнопки находятся в состоянии наведения, они становятся синими. На сенсорных устройствах, таких как iPad, состояние зависания остается липким, поэтому кнопка остается синей после нажатия на нее. Я этого не хочу.

  • Я мог бы добавить no-hover класс ontouchend для каждой кнопки и сделайте мой CSS такой: button:not(.no-hover):hover { background-color: blue; }, но это, вероятно, очень плохо для производительности, и не делает обрабатывать устройства, такие как Chromebook Pixel (который имеет как сенсорный экран и мышь) правильно.

  • Я мог бы добавить класс touch к documentElement и сделаю мой CSS как это: html:not(.touch) button:hover { background-color: blue; } Но это также не работает на устройствах с сенсорным и мыши.

Я бы предпочел удалить состояние наведения ontouchend. Но не похоже, что это возможно. Фокусировка на другом элементе не устраняет состояние наведения. Касание другого элемента выполняется вручную, но я не могу вызвать это в JavaScript.

Все решения, которые я нашел, кажутся несовершенными. Есть ли идеальное решение?

114 голосов | спросил Chris 21 J0000006Europe/Moscow 2013, 15:10:40

18 ответов


0

Вы можете удалить состояние наведения, временно удалив ссылку из DOM. См. http://testbug.handcraft.com/ipad.html


В CSS у вас есть:

:hover {background:red;}

В JS у вас есть:

function fix()
{
    var el = this;
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    setTimeout(function() {par.insertBefore(el, next);}, 0)
}

А затем в вашем HTML вы получите:

<a href="#" ontouchend="this.onclick=fix">test</a>
ответил 17 +04002014-10-17T12:39:00+04:00312014bEurope/MoscowFri, 17 Oct 2014 12:39:00 +0400 2014, 12:39:00
0

Как только CSS Media Queries Level 4 будет реализован, вы сможете сделать это

@media (hover: hover) {
    button:hover {
        background-color: blue;
    }
}

Или по-английски: «Если браузер поддерживает правильное /истинное /реальное /неэмулируемое наведение (например, имеет основное устройство ввода, похожее на мышь), тогда примените этот стиль, когда button находятся над. "

Поскольку эта часть Media Queries Level 4 до сих пор была реализована только в новейшем Chrome, Я написал полифилл , чтобы разобраться с этим. Используя его, вы можете преобразовать вышеупомянутый футуристический CSS в:

html.my-true-hover button:hover {
    background-color: blue;
}

(Разновидность метода .no-touch) и затем использование некоторого клиентского JavaScript из того же многогранника, который обнаруживает поддержку зависания, Вы можете переключать присутствие класса my-true-hover соответственно:

$(document).on('mq4hsChange', function (e) {
    $(document.documentElement).toggleClass('my-true-hover', e.trueHover);
});
ответил cvrebert 21 Jam1000000amWed, 21 Jan 2015 06:01:24 +030015 2015, 06:01:24
0

Это обычная проблема без идеального решения. Поведение при наведении курсора полезно с помощью мыши и в основном вредно при прикосновении. Усугубляют проблему устройства, поддерживающие сенсорное управление и мышь (одновременно, не меньше!), Такие как Chromebook Pixel и Surface.

Самое чистое решение, которое я нашел, - включить поведение при наведении, если устройство не поддерживает сенсорный ввод.

var isTouch =  !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;

if( !isTouch ){
    // add class which defines hover behavior
}

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

Я проверял это на iPhone, iPad, Chromebook Pixel, Surface и на различных устройствах Android. Я не могу гарантировать, что он будет работать, когда к миксу добавится универсальный сенсорный ввод USB (например, стилус).

ответил Tim Medora 31 +04002013-10-31T23:50:12+04:00312013bEurope/MoscowThu, 31 Oct 2013 23:50:12 +0400 2013, 23:50:12
0

С помощью Modernizr вы можете настроить таргетинг именно на устройства без сенсорного экрана.

(Примечание: это не работает в системе сниппетов StackOverflow, вместо этого проверьте jsfiddle )

/* this one is sticky */
#regular:hover, #regular:active {
  opacity: 0.5;
}

/* this one isn't */
html.no-touch #no-touch:hover, #no-touch:active {
  opacity: 0.5;
}

Обратите внимание, что :active не нужно указывать с помощью .no-touch, так как он работает как на мобильном, так и на настольном компьютере.

ответил rachel 25 22014vEurope/Moscow11bEurope/MoscowTue, 25 Nov 2014 22:00:29 +0300 2014, 22:00:29
0

Из 4 способов борьбы с зависанием на мобильных устройствах : Вот способ динамически добавить или удалить класс «can touch» к документу на основе текущего типа ввода пользователя. Он также работает с гибридными устройствами, когда пользователь может переключаться между касанием и мышью /трекпадом:

<script>

;(function(){
    var isTouch = false //var to indicate current input type (is touch versus no touch) 
    var isTouchTimer 
    var curRootClass = '' //var indicating current document root class ("can-touch" or "")

    function addtouchclass(e){
        clearTimeout(isTouchTimer)
        isTouch = true
        if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present
            curRootClass = 'can-touch'
            document.documentElement.classList.add(curRootClass)
        }
        isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event
    }

    function removetouchclass(e){
        if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present
            isTouch = false
            curRootClass = ''
            document.documentElement.classList.remove('can-touch')
        }
    }

    document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch
    document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad
})();

</script>
ответил coco puffs 22 J000000Friday16 2016, 00:20:26
0
$("#elementwithhover").click(function() { 
  // code that makes element or parent slide or otherwise move out from under mouse. 

  $(this).clone(true).insertAfter($(this));
  $(this).remove();
});
ответил Verard Sloggett 29 J000000Wednesday15 2015, 07:49:03
0

Я собирался опубликовать свое собственное решение, но, проверив, уже кто-то опубликовал его, я обнаружил, что @Rodney почти сделал это. Тем не менее, он пропустил последний момент, который сделал его бесполезным, по крайней мере, в моем случае. Я имею в виду, я тоже взял то же самое .fakeHover добавление /удаление класса через mouseenter и mouseleave обнаружение событий, но само по себе, как таковое , действует почти точно как "подлинный" :hover. Я имею в виду: когда вы нажимаете на элемент в вашей таблице, он не обнаружит, что вы его «бросили» - таким образом, сохраняя состояние «поддельного».

Я просто прослушал click, поэтому, когда я «нажимаю» на кнопку, я вручную запускаю ---- +: = 5 =:. + ----

Si, это мой окончательный код:

mouseleave


.fakeHover {
    background-color: blue;
}

Таким образом вы сохраняете свои обычные функции $(document).on('mouseenter', 'button.myButton',function(){ $(this).addClass('fakeHover'); }); $(document).on('mouseleave', 'button.myButton',function(){ $(this).removeClass('fakeHover'); }); $(document).on('button.myButton, 'click', function(){ $(this).mouseleave(); }); при использовании мыши, когда вы просто «зависаете» на своих кнопках. Ну, почти все: единственный недостаток в том, что после нажатия кнопки мышью она не будет в состоянии hover , Как если бы вы нажали и быстро вынули указатель из кнопки. Но в моем случае я могу жить с этим.

ответил Pere 1 J0000006Europe/Moscow 2016, 21:02:16
0

Это было полезно для меня: ссылка

function hoverTouchUnstick() {
    // Check if the device supports touch events
    if('ontouchstart' in document.documentElement) {
        // Loop through each stylesheet
        for(var sheetI = document.styleSheets.length - 1; sheetI >= 0; sheetI--) {
            var sheet = document.styleSheets[sheetI];
            // Verify if cssRules exists in sheet
            if(sheet.cssRules) {
                // Loop through each rule in sheet
                for(var ruleI = sheet.cssRules.length - 1; ruleI >= 0; ruleI--) {
                    var rule = sheet.cssRules[ruleI];
                    // Verify rule has selector text
                    if(rule.selectorText) {
                        // Replace hover psuedo-class with active psuedo-class
                        rule.selectorText = rule.selectorText.replace(":hover", ":active");
                    }
                }
            }
        }
    }
}
ответил mineroot 6 J000000Monday15 2015, 17:55:40
0

Добавьте этот код JS на свою страницу:

document.body.className = 'ontouchstart' in document.documentElement ? '' : 'hover';

теперь в вашем CSS перед каждым наведением добавьте класс наведения так:

.hover .foo:hover {}

Если устройство сенсорное, класс тела будет пустым, в противном случае его класс будет зависать и правила будут применены!

ответил Ali 6 SunEurope/Moscow2015-12-06T03:22:16+03:00Europe/Moscow12bEurope/MoscowSun, 06 Dec 2015 03:22:16 +0300 2015, 03:22:16
0
  

Я мог бы добавить к каждой кнопке однокурсный класс без указателя мыши и сделать мой CSS-код похожим на> this: button: not (.no-hover): hover {background-color:   синий; } но это, вероятно, очень плохо сказывается на производительности и не обрабатывает> устройства, такие как Chromebook Pixel (с сенсорным экраном и мышью)> правильно.

Это правильная отправная точка. Следующий шаг: применять /удалять класс nohover для следующих событий (демонстрация с jQuery)

buttonelement
 .on("touchend touchcancel",function(){$(this).addClass("nohover")})
 .on("touchstart mouseover",function({$(this).removeClass("nohover")});   

Примечание. Если вы хотите применить другие классы к элементу buttonelement, то: not (.nohover) в CSS больше не будет работать должным образом. Чем вы должны добавить вместо этого отдельное определение со значением по умолчанию и! Важным тегом для перезаписи стиля наведения:      .nohover {фоновый цвет: белый! важный}

Это должно правильно работать даже с такими устройствами, как Chromebook Pixel (с сенсорным экраном и мышью)! И я не думаю, что это главный убийца производительности ...

ответил Sascha Hendel 10 MarpmThu, 10 Mar 2016 17:39:56 +03002016-03-10T17:39:56+03:0005 2016, 17:39:56
0

Решение, которое сработало для меня:

html {
   -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

Добавьте этот код в таблицу стилей.

Я хотел избавиться от серого фона, который появляется в iOS Safari при нажатии на ссылку. Но, похоже, сделать больше. Теперь нажатие кнопки (с псевдоклассом :hover!) Открывается сразу же! Я тестировал его только на iPad, не знаю, будет ли он работать на других устройствах.

ответил Leon Vogler 19 MarpmSat, 19 Mar 2016 21:04:20 +03002016-03-19T21:04:20+03:0009 2016, 21:04:20
0

Это то, что я придумал после изучения остальных ответов. Он должен поддерживать только сенсорные, мышиные или гибридные пользователи.

Создайте отдельный класс наведения для эффекта наведения. По умолчанию добавьте этот класс наведения к нашей кнопке.

Мы не хотим обнаруживать наличие сенсорной поддержки и отключать все эффекты наведения с самого начала. Как уже упоминалось, гибридные устройства набирают популярность; люди могут иметь сенсорную поддержку, но хотят использовать мышь и наоборот. Поэтому удаляйте класс при наведении, только когда пользователь фактически нажимает кнопку.

Следующая проблема в том, что если пользователь захочет вернуться к использованию мыши после нажатия кнопки? Чтобы решить эту проблему, нам нужно найти подходящий момент, чтобы добавить обратно класс hover, который мы удалили.

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

Итак, я подумал об использовании алгоритма ожидания занятости (используя setInterval) для проверки состояния наведения. После того, как состояние наведения отключено, мы можем добавить обратно класс наведения и остановить ожидание занятости, возвращая нас в исходное состояние, в котором пользователь может использовать мышь или касание.

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

 var button = document.getElementById('myButton');

button.ontouchstart = function(e) {
  console.log('ontouchstart');
  $('.button').removeClass('button-hover');
  startIntervalToResetHover();
};

button.onclick = function(e) {
  console.log('onclick');
}

var intervalId;

function startIntervalToResetHover() {
  // Clear the previous one, if any.
  if (intervalId) {
    clearInterval(intervalId);
  }
  
  intervalId = setInterval(function() {
    // Stop if the hover class already exists.
    if ($('.button').hasClass('button-hover')) {
      clearInterval(intervalId);
      intervalId = null;
      return;
    }
    
    // Checking of hover state from 
    // http://stackoverflow.com/a/8981521/2669960.
    var isHovered = !!$('.button').filter(function() {
      return $(this).is(":hover");
    }).length;
    
    if (isHovered) {
      console.log('Hover state is active');
    } else {
      console.log('Hover state is inactive');
      $('.button').addClass('button-hover');
      console.log('Added back the button-hover class');
      
      clearInterval(intervalId);
      intervalId = null;
    }
  }, 1000);
}
 .button {
  color: green;
  border: none;
}

.button-hover:hover {
  background: yellow;
  border: none;
}

.button:active {
  border: none;
}
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='myButton' class='button button-hover'>Hello</button>

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

ответил Kevin Lee 28 J000000Thursday16 2016, 10:54:39
0

Вы можете установить цвет фона в состоянии :active и задать :focus фон по умолчанию.

если вы установите цвет фона с помощью onfocus/ontouch, стиль цвета останется один раз :focus состояние прошло.
Вам также необходимо выполнить сброс для onblur, чтобы восстановить значение по умолчанию bg при потере фокуса.

ответил G-Cyr 21 J0000006Europe/Moscow 2013, 15:17:00
0

Это сработало для меня: поместите стиль наведения в новый класс

.fakehover {background: red}

Затем добавьте /удалите класс по мере необходимости

$(".someclass > li").on("mouseenter", function(e) {
  $(this).addClass("fakehover");
});
$(".someclass > li").on("mouseleave", function(e) {
  $(this).removeClass("fakehover");
});

Повторите эти действия для событий touchstart и touchend. Или любые другие события, которые вам нравятся, чтобы получить желаемый результат, например, я хотел, чтобы эффект зависания был переключен на сенсорном экране.

ответил Rodney 17 J000000Friday15 2015, 14:07:08
0

На основе ответа Даррена Кука, который также работает, если вы наведете палец на другой элемент.

См. Поиск элемента во время события касания

jQuery(function() {
    FastClick.attach(document.body);
});
// Prevent sticky hover effects for buttons on touch devices
// From https://stackoverflow.com/a/17234319
//
//
// Usage:
// <a href="..." touch-focus-fix>..</a>
//
// Refactored from a directive for better performance and compability
jQuery(document.documentElement).on('touchend', function(event) {
  'use strict';

  function fix(sourceElement) {
    var el = $(sourceElement).closest('[touch-focus-fix]')[0];
    if (!el) {
      return;
    }
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    par.insertBefore(el, next);
  }

  fix(event.target);
  var changedTouch = event.originalEvent.changedTouches[0];
  // http://www.w3.org/TR/2011/WD-touch-events-20110505/#the-touchend-event
  if (!changedTouch) {
    return;
  }
  var touchTarget = document.elementFromPoint(changedTouch.clientX, changedTouch.clientY);
  if (touchTarget && touchTarget !== event.target) {
    fix(touchTarget);
  }
});

Демонстрация Codepen

ответил jantimon 28 AMpThu, 28 Apr 2016 11:47:12 +030047Thursday 2016, 11:47:12
0

Вы можете попробовать это так.

JavaScript:

var isEventSupported = function (eventName, elementName) {
    var el = elementName ? document.createElement(elementName) : window;
    eventName = 'on' + eventName;
    var isSupported = (eventName in el);
    if (!isSupported && el.setAttribute) {
        el.setAttribute(eventName, 'return;');
        isSupported = typeof el[eventName] == 'function';
    }
    el = null;
    return isSupported;
};

if (!isEventSupported('touchstart')) {
    $('a').addClass('with-hover');
}

CSS

a.with-hover:hover {
  color: #fafafa;
}
ответил Lorenzo Polidori 30 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 30 Sep 2016 11:44:40 +0300 2016, 11:44:40
0

То, что я до сих пор делал в своих проектах, состояло в том, чтобы отменить изменения :hover на сенсорных устройствах:

.myhoveredclass {
    background-color:green;
}
.myhoveredclass:hover {
    background-color:red;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
    .myhoveredclass:hover, .myhoveredclass:active, .myhoveredclass:focus {
        background-color:green;
    }
}

Все имена классов и именованные цвета только для демонстрационных целей; -)

ответил z00l 25 SunEurope/Moscow2016-12-25T23:47:51+03:00Europe/Moscow12bEurope/MoscowSun, 25 Dec 2016 23:47:51 +0300 2016, 23:47:51
0

У меня есть хорошее решение, которым я хотел бы поделиться. Сначала вам нужно определить, находится ли пользователь на мобильном телефоне, например:

var touchDevice = /ipad|iphone|android|windows phone|blackberry/i.test(navigator.userAgent.toLowerCase());

Тогда просто добавьте:

if (!touchDevice) {
    $(".navbar-ul").addClass("hoverable");
}

И в CSS:

.navbar-ul.hoverable li a:hover {
    color: #fff;
}
ответил Michał Reszka 9 52018vEurope/Moscow11bEurope/MoscowFri, 09 Nov 2018 12:28:50 +0300 2018, 12:28:50

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132