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

IT技术 javascript css hover touch
2021-01-25 04:58:42

我创建了一个带有始终可见的上一个和下一个按钮的轮播。这些按钮有一个悬停状态,它们变成蓝色。在 iPad 等触控设备上,悬停状态是粘性的,因此点击按钮后按钮会保持蓝色。我不想要那个。

  • 我可以为每个按钮添加一个no-hoverontouchend,并使我的 CSS 像这样:button:not(.no-hover):hover { background-color: blue; }但这可能对性能很不利,并且不能正确处理像 Chromebook Pixel(具有触摸屏和鼠标)之类的设备。

  • 我可以向 中添加一个touchdocumentElement并使我的 CSS 像这样:html:not(.touch) button:hover { background-color: blue; }但这也不适用于同时具有触摸和鼠标的设备。

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

我找到的所有解决方案似乎都不完美。有没有完美的解决方案?

6个回答

由于这部分CSS Media Queries Level 4自 2018 年以来已经广泛实施,您可以使用:

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

或用英语:“如果浏览器支持正确/真实/真实/非模拟悬停(例如,具有类似鼠标的主要输入设备),则button在悬停 s时应用此样式。”

对于没有实现这个的浏览器(或者在这个原始答案的时候没有实现),我写了一个 polyfill来处理这个问题。使用它,您可以将上述未来派 CSS 转换为:

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

(该.no-touch技术的一种变体)然后使用来自同一个 polyfill 的一些客户端 JavaScript 来检测对悬停的支持,您可以相应地切换my-true-hover的存在

$(document).on('mq4hsChange', function (e) {
    $(document.documentElement).toggleClass('my-true-hover', e.trueHover);
});
谢谢!就我而言,这似乎在大多数浏览器caniuse.com/#search=media%20queries 中都受支持并且效果很好,谢谢!
2021-03-20 04:58:42
这实际上并不能解决双输入设备的问题。(我是从 Surface Book 2 写的。)您可以在通过触摸按下按钮后移动鼠标/触摸板,但这是一个粗制滥造的修复。我们真的需要一个仅适用于带指针悬停的伪类。
2021-03-21 04:58:42
你需要查看caniuse.com/#feat=css-media-interaction,你会发现它在 Firefox 和 IE11 中不受支持:( 所以你需要 polyfill
2021-03-22 04:58:42
这现在在移动浏览器中得到广泛支持,并且效果很好。我认为这应该是公认的答案。
2021-03-24 04:58:42
似乎不再支持 polyfill(repo 已存档)并且它需要 jQuery ...
2021-04-01 04:58:42

您可以通过从 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>
@DarrenCook 但是这是删除元素并重新添加它的好主意吗?我想这会导致“卡顿”并与应用程序的 60fps 黄油平滑需求发生冲突。
2021-03-18 04:58:42
@Chris 好点,我更改了示例以在 ontouchend 事件中设置 onclick 处理程序。
2021-03-21 04:58:42
@KevinBorders 是的,在某些设备上,移除和重新插入元素之间的时间延迟可能非常明显。不幸的是,我在我的 android 4.4 设备上发现在没有 setTimeout 的情况下这样做是行不通的。
2021-04-02 04:58:42
请考虑在您的答案中添加最少的演示代码。谢谢!stackoverflow.com/help/how-to-answer
2021-04-05 04:58:42
@SjoerdVisscher 我已经粘贴了它。StackOverflow 喜欢答案中的代码,因为链接可以消失。(在这种情况下,它不仅需要点击,还需要查看源代码,并找出哪些位是有问题的技术。)
2021-04-14 04:58:42

这是一个普遍的问题,没有完美的解决方案。悬停行为对鼠标很有用,而对触摸则最不利。使问题更加复杂的是支持触摸和鼠标(同时,不少于!)的设备,如 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 触摸输入(例如手写笔)添加到混合中时它会起作用。

好答案。这是一个类似的解决方案:stackoverflow.com/a/39787268/885464
2021-03-20 04:58:42
不错的解决方案!但不适用于同时支持触摸和鼠标的设备。
2021-03-22 04:58:42
太棒了,这对我有用,不像社区 wiki/Darren Cook 的回答。
2021-04-01 04:58:42

您可以覆盖不支持悬停的设备的悬停效果。喜欢:

.my-thing {
    color: #BADA55;
}

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

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

在 iOS 12 上测试和验证

帽子提示https://stackoverflow.com/a/50285058/178959指出这一点。

还要检查:css-tricks.com/...
2021-03-16 04:58:42
这是更现代的解决方案,不需要 javascript 或 DOM 操作,具有完整的浏览器支持(IE 除外),应该是公认的答案。
2021-03-27 04:58:42
这也没有解决双模设备(触摸屏笔记本电脑等)。 hover: none如果浏览器同时具有触摸和指针输入,则不会为真。
2021-04-14 04:58:42

使用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因为它在移动设备和桌面设备上都可以正常工作。

我想一种方法是同时使用 Modernizr 以及诸如mobile-detect.js 之类的库来确保它是手机或平板电脑。
2021-03-16 04:58:42
这不能解决多输入设备的问题。no-touch课程适用于我的 Surface Book 2(触控板 + 触摸屏),但:hover规则仍然保留在您的小提琴链接中。
2021-03-18 04:58:42
问题是,现在带有触摸屏的支持鼠标的设备随处可见,你不能再依赖这种方法了。但是,我看不到太多其他方法来做到这一点......这是一个两难境地
2021-03-25 04:58:42
这是 IMO 的最佳答案,但该示例不正确。它为触摸和非触摸设备显示相同的悬停状态。如果.no-touch存在于html标签上,它应该只应用悬停状态否则,这个答案会得到我的认可。
2021-03-27 04:58:42
你是救世主,非常感谢这对移动设备非常有效
2021-03-27 04:58:42