如何防止触摸设备上按钮的粘滞悬停效果

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何防止触摸设备上按钮的粘滞悬停效果相关的知识,希望对你有一定的参考价值。

我创建了一个带有前一个和下一个按钮的旋转木马,它们始终可见。这些按钮具有悬停状态,它们变为蓝色。在触控设备(如iPad)上,悬停状态是粘性的,因此按下按钮后按钮会保持蓝色。我不希望这样。

  • 我可以为每个按钮添加一个no-hoverontouchend,并使我的CSS像这样:button:not(.no-hover):hover { background-color: blue; }但这可能对性能非常不利,并且不能正确处理Chromebook Pixel(同时具有触摸屏和鼠标)等设备。
  • 我可以在touch上添加一个documentElement类,并使我的CSS像这样:html:not(.touch) button:hover { background-color: blue; }但是这也无法在具有触摸和鼠标的设备上正常工作。

我更喜欢的是删除悬停状态ontouchend。但这似乎不太可能。聚焦另一个元素不会消除悬停状态。手动点击另一个元素,但我似乎无法在javascript中触发它。

我发现的所有解决方案似乎都不完美。有完美的解决方案吗?

答案

您可以通过暂时从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>
另一答案

将此JS代码添加到您的页面:

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

现在在你的CSS之前每次悬停添加像这样的悬停类:

.hover .foo:hover {}

如果设备是触摸的,则body类将为空,否则其类将悬停并应用规则!

另一答案

我可以为每个按钮添加一个无悬停类ontouchend,并使我的CSS像> this: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,则CSS中的not(.nohover)将不再按预期工作。比你必须添加一个单独的定义与默认值和!important标签来覆盖悬停样式:.nohover {background-color:white!important}

这甚至可以正确处理Chromebook Pixel(同时具有触摸屏和鼠标)等设备!我不认为,这是一个主要的性能杀手......

另一答案

一个对我有用的解决方案:

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

将此代码添加到样式表中。

我想摆脱点击链接时ios Safari上出现的灰色背景。但它似乎做得更多。现在点击一个按钮(带有:hover伪类!)立即打开!我只是在iPad上测试过,我不知道它是否适用于其他设备。

另一答案

我想我找到了一个类似问题的优雅(最小js)解决方案:

使用jQuery,您可以使用.mouseover()触发悬停在body(或任何其他元素)上

所以我只是将这个处理程序附加到元素的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>
另一答案

这是我在研究其余答案后到目前为止所提出的。它应该能够支持仅触摸,仅鼠标或混合用户。

为悬停效果创建单独的悬停类。默认情况下,将此悬停类添加到我们的按钮。

我们不希望检测触摸支持的存在并从一开始就禁用所有悬停效果。正如其他人所提到的,混合设备越来越受欢迎;人们可能有触摸支持,但想要使用鼠标,反之亦然。因此,仅在用户实际触摸按钮时删除悬停类。

接下来的问题是,如果用户想要在触摸按钮后返回使用鼠标怎么办?要解决这个问题,我们需要找到一个适当的时机来添加我们已删除的悬停类。

但是,我们无法在删除它后立即将其添加回来,因为悬停状态仍处于活动状态。我们可能也不想破坏和重新创建整个按钮。

所以,我想过使用忙等待算法(使用setInterval)来检查悬停状态。一旦停用悬停状态,我们就可以添加回悬停类并停止忙等待,使我们回到用户可以使用鼠标或触摸的原始状态。

我知道忙碌的等待不是很好,但我不确定是否有适当的事件。我考虑过将它添加回mouseleave事件,但它不是很强大。例如,当触摸按钮后弹出警报时,鼠标位置会移动但不会触发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>
另一答案

您可以在:active状态下设置背景颜色,并为:focus提供defaut背景。

如果你通过onfocus/ontouch设置背景颜色,一旦:focus状态消失,颜色样式仍然存在。 您需要重置onblur以便在焦点丢失时恢复defaut bg。

另一答案

这对我有用:将悬停样式放在一个新类中

.fakehover {background: red}

然后在需要时添加/删除类

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

重复touchstart和touchend事件。或者您喜欢的任何事件以获得所需的结果,例如我希望在触摸屏上切换悬停效果。

另一答案

根据Darren Cooks的答案,如果你将手指放在另一个元素上,这个答案也会有效。

Find element finger is on during a touchend event

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

另一答案

你可以试试这种方式。

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;
}
另一答案

到目前为止我在我的项目中做的是恢复触摸设备上的:hover更改:

.myhoveredclass {
   

以上是关于如何防止触摸设备上按钮的粘滞悬停效果的主要内容,如果未能解决你的问题,请参考以下文章

按钮上的 chrome 中的粘滞悬停状态

桌面悬停媒体查询不能防止粘滞悬停

如何在触摸设备上模拟悬停效果?

按钮悬停效果和触摸 (WPF)

触摸屏设备上的 CSS 悬停不会被忽略

jquery防止触摸悬停功能