共计 4130 个字符,预计需要花费 11 分钟才能阅读完成。
浅谈 :hover 伪类选择器在 touch 环境如何禁止失效的问题
:hover
伪类选择器用于定义元素被鼠标悬停时的款式,但它在 touch 触屏操作的环境下体现就不是那么让人称心了,次要是触屏操作并不像鼠标那样有所谓的悬停状态,所以得点击后能力失效,它也没有像鼠标挪开这样的概念,所以得等到元素失焦后才会生效,这就造成了有时款式并不合乎预期后果的状况,因而有人会心愿触屏操作时不要让这个选择器失效,而本篇文章就来探讨一下如何实现这一点。
01. 应用 @media 媒体查问
从 Media Queries Level 4 开始,浏览器新增了 hover
的查问条件,用于检测以后环境的 “ 次要 ” 输出设施是否反对 :hover
选择器,它有 hover
和 none
两个值,前者是合乎而后者是不合乎,因而应用 @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