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


144

Я создал карусель с предыдущей и следующей кнопками, которые всегда видны. Эти кнопки находятся в состоянии наведения, они становятся синими. На сенсорных устройствах, таких как 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.

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

Ответы:


55

Вы можете удалить состояние наведения, временно удалив ссылку из 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>

3
@ Chris Хороший вопрос, я изменил пример, чтобы установить обработчик onclick в событии ontouchend.
Sjoerd Visscher

4
Пожалуйста, рассмотрите возможность добавления минимального демонстрационного кода в ваш ответ. Спасибо! stackoverflow.com/help/how-to-answer
2540625

1
@SjoerdVisscher Я вставил его. StackOverflow нравится код в ответе, так как ссылки могут исчезнуть. (И в этом случае потребовалось не просто просмотреть, а затем просмотреть источник и выяснить, какие биты являются рассматриваемой техникой.)
Даррен Кук

2
@KevinBorders yes На некоторых устройствах задержка между удалением и повторной вставкой элемента может быть очень заметной. К сожалению, я обнаружил на своем устройстве Android 4.4, что это сделать без setTimeout не работает.
Родни

1
Идея интересная, но я нахожу ее несколько вялой и не поддерживается на всех сенсорных устройствах. Я бы предпочел менее инвазивное решение, основанное на обнаружении сенсорной поддержки и чистом CSS, как этот stackoverflow.com/a/39787268/885464
Лоренцо Полидори

83

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

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

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

Поскольку эта часть 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);
});

Спасибо! Для моих целей это, кажется, поддерживается в большинстве браузеров caniuse.com/#search=media%20queries и отлично работает, спасибо!
ragamufin

3
Вам нужно посмотреть на Вместо этого вам caniuse.com/#feat=css-media-interaction, и вы увидите, что он не поддерживается в Firefox и IE11 :( поэтому вам нужен полифилл
CherryDT

Кажется, что polyfill больше не поддерживается (репо заархивирован), и для него требуется jQuery ...
amoebe

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

Это, безусловно, самый простой для реализации и лучший ответ. Работает в Firefox на Android Mobile и ПК. Не уверен насчет устройств с двойным касанием и мышью.
HalfMens

28

Это обычная проблема без идеального решения. Поведение при наведении курсора полезно с мышью и в основном вредно при касании. Усугубляют проблему устройства, поддерживающие сенсорное управление и мышь (одновременно, не меньше!), Такие как 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 (например, стилус).


1
Круто, это сработало для меня, в отличие от ответа сообщества вики / Даррена Кука.
Jannik

1
Хороший ответ. Это похожее решение: stackoverflow.com/a/39787268/885464
Лоренцо Полидори

11

С 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так как он работает как на мобильном, так и на настольном компьютере.


Это лучший ответ IMO, но пример неверный. Он показывает одинаковое состояние наведения для сенсорных и не сенсорных устройств. Следует применять только состояние наведения, если .no-touchоно присутствует в htmlтеге. В противном случае этот ответ получит мою печать одобрения.
Моррисбрет

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

Я полагаю, что один из способов сделать это - использовать Modernizr, а также библиотеку, такую ​​как mobile-detect.js, чтобы убедиться, что это либо телефон, либо планшет.
Гэвин

Вы спаситель люди , большое спасибо это работало отлично для мобильных устройств
Шивы

9

Вы можете переопределить эффект наведения для устройств, которые не поддерживают наведение. Подобно:

.my-thing {
    color: #BADA55;
}

.my-thing:hover {
    color: hotpink;
}

@media (hover: none) {
    .my-thing {
        color: #BADA55;
    }
}

Протестировано и проверено на iOS 12

Шляпа для https://stackoverflow.com/a/50285058/178959 за указание на это.


Это более современное решение, не требующее JavaScript или манипулирование DOM, имеет полную поддержку браузера (кроме IE) и должно быть принятым ответом.
Funkju

8
$("#elementwithhover").click(function() { 
  // code that makes element or parent slide or otherwise move out from under mouse. 

  $(this).clone(true).insertAfter($(this));
  $(this).remove();
});

Вы можете улучшить этот ответ, используя on () вместо click (). Удалив элемент из DOM и повторно прикрепив его, я потерял события щелчка. Когда я переписал свою функцию с помощью, привязка к элементу, затем удаление и добавление работали. Например: `$ ('body'). On ('click', '# elementwithhover', function () {// clone, inserttafter, remove}); Я проголосую, если вы сделаете это изменение.
Будет Ланни

Значение true для клона сохраняет событие click для нового элемента, занимающего место элемента с зависшим курсором. оригинальный элемент удаляется из домена после его клонирования.
Верард Слоггетт

офигенно, 10х
Калоян Стаматов

Часы поиска исправления, и это, наконец, обеспечило одно. Бесконечно благодарен!
phil917

8

Из 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>

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

3

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

Я тоже просто слушал click, поэтому, когда я «нажимаю» на кнопку, я вручную запускаю a mouseleave.

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

.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функциональность при использовании мыши, когда просто «зависаете» на кнопках. Ну, почти все: единственный недостаток в том, что после нажатия кнопки мышью она не будет в hoverсостоянии. Как если бы вы нажали и быстро вынули указатель из кнопки. Но в моем случае я могу жить с этим.


2

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

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

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

Следующая проблема заключается в том, что если пользователь захочет вернуться к использованию мыши после нажатия кнопки? Чтобы решить эту проблему, нам нужно найти подходящий момент, чтобы добавить обратно класс 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. Не очень чистое решение.


1

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

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

Вам нужно вызвать hoverTouchUnstick () один раз из глобального обработчика события ontouchstart. И это решение будет работать отлично.
Джусид

1

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

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

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

.hover .foo:hover {}

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


У меня не сработало, но это document.body.className = 'ontouchstart' in window ? '' : 'hover';
сработало

1

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

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

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

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

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


1

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

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

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

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


1

Я думаю, что нашел элегантное (минимум JS) решение для аналогичной проблемы:

Используя jQuery, вы можете запустить hover на теле (или любом другом элементе), используя .mouseover()

Поэтому я просто присоединяю этот обработчик к ontouchendсобытию элемента следующим образом:

var unhover = function() {
  $("body").mousover();  
};
.hoverable {
  width: 100px;
  height: 100px;
  background: teal;
  cursor: pointer;
}

.hoverable:hover {
  background: pink;
}
<div class="hoverable" ontouchend={unhover}></div>

Это, однако, удаляет псевдокласс: hover из элемента только после запуска какого-либо другого события касания, например, удара или другого касания


1
Для вашего фрагмента кода квадрат все еще остается розовым после того, как я коснулся его. Я полагаю, вы не решили проблему, заданную в этом вопросе?
Кевин Ли,

Это решение не работает. Во-первых, вы использовали неправильный метод для вызова события, вы должны использовать .trigger () . Во-вторых, в любом случае не работает на мобильном сафари.
xHocquet

1

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

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

2
Не работает на гибридных устройствах, например ПК с сенсорным экраном Windows.
cspolton

1

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

Мы использовали SCSS в нашем приложении. и я определил миксин, чтобы позаботиться о сенсорном устройстве.

@mixin hover-support {
  @media not all and (pointer: coarse) {
    &:hover {
      @content;
    }
  }
}

и затем я поместил все свои классы CSS под нижеупомянутый фрагмент.

   @include hover-support() {
    // Your css-classes or css that you want to apply on those devices that support hover.
   }

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

@include hover-support() {
  .animate-icon {
    -webkit-transition: all 0.2s;
    transition: all 0.2s;
    &:hover {
      transform: scale(1.3);
      filter: brightness(85%);
      cursor: pointer;
    }
  }
}

1

Вот простой код JavaScript, который не требует от разработчика редактирования CSS или написания новых правил CSS. Я написал это для кнопок Bootstrap с помощью кнопки class="btn", но она будет работать с любой кнопкой с определенным именем класса.

Шаги:

  1. определить, является ли это сенсорным устройством
  2. если это так, переберите каждое правило CSS в document.styleSheets
  3. удалить любое правило, содержащее .btnи:hover

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

Шаг 1. Обнаружение сенсорного устройства

Проверьте медиа-запрос на наличие (hover: none):

    const hasMatchMedia = typeof window.matchMedia !== 'undefined';
    /**
     * determine if device is touch-capable
     * true - device is touch-capable
     * false - device is not touch-capable
     * null - unable to determine touch capability
     * @return {null|boolean}
     */
    const hasTouch = () => {
      if (hasMatchMedia) {
        return window.matchMedia('(hover: none)').matches;
      }
      return null;
    };

Шаг 2: Удалить правила CSS, содержащие `btn` и`: hover`

    /**
     * remove all CSS rules contaning both '.btn' and ':hover'
     * @return {number} count of rules deleted
     */
    function removeBtnHovers () {

      let rulesDeleted = 0;

      // recursively delete '.btn:hover' rules
      function recursiveDelete (rules, styleSheet) {

        if (typeof rules === 'undefined' ||
          typeof rules.length === 'undefined' ||
          rules.length <= 0) {
          return;
        }

        // iterate in reverse order,
        // deleting any rule containing both '.btn' and ':hover'
        const ruleLen = rules.length;
        for (let i = ruleLen - 1; i >= 0; i--) {
          const rule = rules[i];
          if (typeof rule.cssRules === 'undefined') {
            // a standard rule, evaluate it
            const cssText = rule.cssText;
            if (typeof cssText === 'string' &&
              cssText.includes('.btn') &&
              cssText.includes(':hover')) {
              styleSheet.deleteRule(i);
              rulesDeleted++;
            }
          } else {
            // rule contains cssRules, iterate over them
            recursiveDelete(rule.cssRules, rule);
          }
        }
      }

      // iterate over all style sheets in document
      for (const styleSheet of document.styleSheets) {
        let rules = styleSheet.cssRules;
        if (!rules) { continue; }
        recursiveDelete(rules, styleSheet);
      }
      return rulesDeleted;
    }

Полный код на GitHub и npm .

Живая демоверсия на terrymorse.com .


Разве это не устраняет эффект зависания для устройств с сенсорным экраном с мышью / трекпадом?
Дженсей

@Jensei Возможно. Правила наведения удаляются, если устройство соответствует @media (hover:none)или когда пользователь впервые касается экрана. Вы можете попробовать это на демо-странице, чтобы быть уверенным.
Терримор

0

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

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


Но я бы хотел сохранить эффект наведения мыши для пользователей мыши.
Крис

: hover и: active могут получать один и тот же CSS-код, это: у вас есть проблема. На самом деле, если вы установите цвет фона с помощью onfocus, цветовой стиль останется после того, как фокус исчезнет. вам также нужно сбросить onlur, чтобы восстановить defaut bg
G-Cyrillus

0

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

.fakehover {background: red}

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

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

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


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 Demo


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

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

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


0

Это прекрасно работает в 2 этапа.

  1. Установите свой тег тела, чтобы быть таким <body ontouchstart="">. Я не фанат этого «хака», но он позволяет Safari на iOS мгновенно реагировать на прикосновения. Не уверен, как, но это работает.

  2. Настройте свой осязательный класс следующим образом:

    // I did this in SASS, but this should work with normal CSS as well
    
    // Touchable class
    .example {
    
        // Default styles
        background: green;
    
        // Default hover styles 
        // (Think of this as Desktop and larger)
        &:hover {
            background: yellow;
        }
    
        // Default active styles
        &:active {
            background: red;
        }
    
        // Setup breakpoint for smaller device widths
        @media only screen and (max-width: 1048px) {
    
            // Important!
            // Reset touchable hover styles
            // You may want to use the same exact styles as the Default styles
            &:hover {
                background: green;
            }
    
            // Important!
            // Touchable active styles
            &:active {
                background: red;
            }
        }
    }

Возможно, вы захотите удалить любую анимацию в вашем сенсорном классе. Android Chrome немного медленнее, чем iOS.

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


0

Некоторые из зависших или застрявших :hover :focus :activeпроблем на мобильных устройствах могут быть вызваны отсутствием, <meta name="viewport" content="width=device-width">поскольку браузеры пытаются манипулировать экраном.


0

Для меня решение было после того, как touchend должен был клонировать и заменить узел ... я ненавижу делать это, но даже попытка перекрасить элемент с помощью offsetHeight не работает

    let cloneNode = originNode.cloneNode( true );
    originNode.parentNode.replaceChild( cloneNode, originNode );

В конце концов, это не сработало для меня ... в моем случае мне пришлось бы клонировать весь ES6, который был расширен, и несколько слушателей событий, и это только начало усложняться, чтобы решить такую ​​крошечную вещь.
Запрет

0

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

Мы также можем решить, хотим ли мы парить запускать состояния при при прокрутке касанием (touchmove) или даже добавить тайм-аут, чтобы задержать их.

Единственным существенным изменением в нашем коде будет использование дополнительного класса HTML, например, <a class='hover'></a>элементов, которые реализуют новое поведение.

HTML

<a class='my-link hover' href='#'>
    Test
</a>

CSS

.my-link:active, // :active can be turned off to disable hover state on 'touchmove'
.my-link.hover:hover {

    border: 2px dotted grey;
}

JS (с помощью jQuery)

$('.hover').bind('touchstart', function () {

   var $el;
   $el = $(this);
   $el.removeClass('hover'); 

   $el.hover(null, function () {
      $el.addClass('hover');
   });
});

пример

https://codepen.io/mattrcouk/pen/VweajZv

-

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


0

С 2020 года вы можете добавлять стили наведения в медиа-запрос

@media (hover: hover) and (pointer: fine) {
    /* css hover class/style */
}

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.