关于前端:浅谈-hover-伪类选择器在-touch-环境如何禁止生效的问题

3次阅读

共计 4130 个字符,预计需要花费 11 分钟才能阅读完成。

浅谈 :hover 伪类选择器在 touch 环境如何禁止失效的问题

:hover 伪类选择器用于定义元素被鼠标悬停时的款式,但它在 touch 触屏操作的环境下体现就不是那么让人称心了,次要是触屏操作并不像鼠标那样有所谓的悬停状态,所以得点击后能力失效,它也没有像鼠标挪开这样的概念,所以得等到元素失焦后才会生效,这就造成了有时款式并不合乎预期后果的状况,因而有人会心愿触屏操作时不要让这个选择器失效,而本篇文章就来探讨一下如何实现这一点。


01. 应用 @media 媒体查问

从 Media Queries Level 4 开始,浏览器新增了 hover 的查问条件,用于检测以后环境的 “ 次要 ” 输出设施是否反对 :hover 选择器,它有 hovernone 两个值,前者是合乎而后者是不合乎,因而应用 @media (hover:hover){} 即可实现反对 :hover 选择器的判断,而应用 @media (hover:none){} 则能够实现不反对 :hover 选择器的判断,上面是一个对于该查问条件的简略案例。

<style>
#button01:hover{background-color:#f00;color:#fff;}
@media (hover:hover){#button02:hover{background-color:#f00;color:#fff;} }
</style>

<button id="button01" type="button">button01</button>
<button id="button02" type="button">button02</button>

↓ View & Code ↑

以上截图是在 Windows7 的 Chrome 中操作的后果,咱们为两个按钮都设置了 :hover 款式,当款式失效时背景会变红而文字会变白,但第二个按钮的款式失效条件是次要输出设施反对 :hover 选择器才行,在 PC 模式下因为应用的是鼠标,所以两个按钮在悬停时款式都会失效,但之后咱们切换为挪动模仿状态,此时次要输出设施变换为触屏,因而第二个按钮在被点击后 :hover 款式就不会失效了。

这很完满?其实不然,首先是这个媒体查问条件在一些低版本的浏览器中不被反对,例如说 IE11 就不反对,存在些许兼容问题,其次是有些既反对鼠标又反对触屏的设施如 Surface,在判断 “ 次要 ” 输出设施时有问题,它们默认的次要输出设施是触屏,但插上鼠标后这个判断却不会主动变动,所以就会导致这个查问条件也无奈失效,你能够参考 patrickhlauke.github.io 理解更多对于查问异样的信息。


02. 应用 JavaScript 监听

应用媒体查问的伎俩尽管简略,却存在着一些兼容问题,虽说随着浏览器的降级,在将来兼容必定会有所改善,但目前确是无可奈何,如果你心愿兼容性更好一些,或者能够试着借助 JS,最简略的做法,就是通过绑定 mousemove 事件和 touchstart 事件,当判断到了 mousemove 是在 touchstart 触发了 500 毫秒后才触发的,那就算是应用了鼠标,否则就是应用了触屏,上面是一个简略的例子。

<script>
(function(){

// 代码来自于 StackOverflow,XJ 进行了些许的调整
// https://stackoverflow.com/a/30303898/8079246/
var isMouse = false;  // 是否处于应用 mouse 状态
var lastTouched = 0;  // touchstart 最初触发工夫

// 在 touchstart 触发 500ms 后才触发了 mousemove 
// 就算是应用了鼠标设施,因而增加 isMouse 的类名
document.addEventListener('mousemove', function(){if(isMouse === true || Date.now() - lastTouched <= 500){return};
    document.body.classList.add('isMouse');
    isMouse = true;
}, true);

// 每次触发了 touchstart 就更新 lastTouched 变量
// 每次触发 touchstart 就移除 isMouse 的类名状态
document.addEventListener('touchstart', function(){lastTouched = Date.now();
    if(isMouse === false){return};
    document.body.classList.remove('isMouse');
    isMouse = false;
}, true);

})();
</script>

<style>
#button01:hover{background-color:#f00;color:#fff;}
.isMouse #button02:hover{background-color:#f00;color:#fff;}
</style>

<button id="button01" type="button">button01</button>
<button id="button02" type="button">button02</button>

↓ View & Code ↑

以上截图是在 Windows7 的 Chrome 中操作的后果,咱们为两个按钮都设置了 :hover 款式,当款式失效时背景会变红而文字会变白,但第二个按钮的款式失效条件是存在 isMouse 类名,也就是有鼠标时才失效,在 PC 模式下因为应用的是鼠标,所以两个按钮在悬停时款式都会失效,但之后咱们切换为挪动模仿状态,此时 JS 判断到没有鼠标,因而第二个按钮在被点击后 :hover 款式就不会失效。

这样就行了吧?并不是呢!这种判断存在一个问题,就是当指标节点被按住时,如果按住的工夫超过 500 毫秒,它就会误判为是应用了鼠标设施,并且触屏设施在长按时往往会变成圈选文本或弹出菜单,此时操作就可能会出错,在下面的截图中,最初也展示了长按导致 #button02 谬误响应的状况,那么要如何解决呢?这波及到了不同浏览器的交互细节,切实是不好解决,倡议间接应用现成的插件吧。


03. 应用 xj.operate 计划

XJ 本人编写了一个 xj.operate 插件用于解决本文所聚焦的问题,它有以下三个特点,首先是它存在的目标为了分清以后操作到底是鼠标还是触屏,而不是仅用于判断是否反对 :hover,所以使用范畴就更宽泛了一些,其次是它解决了长按会导致误判的问题,但你也能够通过设置来让长按触发 :hover 变成一种个性,最初是它提供了一些办法,容许咱们临时性的转换状态,以便于实现一些非凡需要。

<!-- 在引入插件后,如果以后环境是应用鼠标进行操作的,html 标签会被增加 xj-operate-mouse 的类名 -->
<script src="https://cdn.jsdelivr.net/gh/xjZone/[email protected]/dist/xj.operate.min.js"></script>

<style>
#button01:hover{background-color:#f00;color:#fff;}
.xj-operate-mouse #button02:hover{background-color:#f00;color:#fff;}
</style>

<button id="button01" type="button">button01</button>
<button id="button02" type="button">button02</button>

↓ View & Code ↑

下面的代码和第二章的代码是雷同的,只是 JS 改成了插件的 CDN,类名从 isMouse 改成了 xj-operate-mouse,在截图中咱们能够看到,在触屏环境下即便长按 #button02 也不会呈现谬误响应的状况了,如果你感觉 xj-operate-mouse 类名太长了,还是心愿应用较短的 isMouse 或其余自定义类名,插件也能通过配置来实现,对于插件更多的细节,能够查看插件的文档,这里就不开展讲了。

实际上业界中也存在其余用于解决 hover 查问兼容的计划,例如说较为闻名的 mq4-hover-shim,但依据 XJ 的实测,发现这个计划也不是很好用,它借助 window.matchMedia() 去判断浏览器是否反对 hover 查问,但咱们在下面第一章节中就说过,有些设施在进行查问时会呈现谬误,所以 window.matchMedia() 的判断可能跟着出错,所以意义并不大,相比之下或者 xj.operate 还更加靠谱些。


参考内容

张鑫旭 – CSS any-hover any-pointer media 查问与交互体验晋升
Patrick H. Lauke – 交互媒体个性及其后劲(对于不正确的假如)

Microsoft – @media 的 hover 查问在 Win11 的 Surface 中有效
bugs.chromium – @media 的 hover 查问在在 Win10 设施上有效

StackOverflow – 如何删除或疏忽在触摸设施上的悬停款式
StackOverflow – 如何避免触摸设施上按钮的粘滞悬停成果
StackOverflow – 如何在挪动端的浏览器上禁用掉悬停成果

MDN – @media hover
MDN – @media any-hover

MDN – @media pointer
MDN – @media any-pointer

MDN – Pointer events
MDN – PointerEvent

patrickhlauke – 对于 @media 媒体查问的 hover / pointer 条件在各种浏览器中的后果测试
patrickhlauke – Touch 相干事件和 Pointer 相干事件在不同环境和不同浏览器中测试的后果

玄魂 –(翻译)整合鼠标、触摸和触控笔事件的 Pointer Event Api
ACGTOFE – 把鼠标、触摸屏、触控笔对立起来,Pointer Events 介绍

xiaoc_ – Surface 笔记本上的手势事件
xiaoc_ – Surface 笔记本上的手势事件

XJ.Chen – xj.operate

正文完
 0