是否有可能强迫忽略:iPhone / iPad用户的hover伪类?

我在我的网站上有一些CSS菜单扩展:hover (不含js)

这在iDevices上以半破解的方式工作,例如,轻击将激活:hover规则并展开菜单,但是在其他地方轻击不会删除:hover 。 另外,如果在元素内部存在链接:hover ,则必须点击两次以激活链接(第一次点击触发:hover ,第二次点击触发链接)。

我已经能够通过绑定touchstart事件在iPhone上很好地工作。

问题是,有时移动Safari仍然会select从CSS触发:hover规则, 而不是我的touchstart事件!

我知道这是问题,因为当我禁用CSS中的所有手动:hover规则时,移动Safari浏览器效果很好(但是常规浏览器显然不再)。

有没有办法dynamic“取消” :hover当用户在移动Safari浏览器的某些元素的:hover规则?

在这里查看和比较iOS行为: http : //jsfiddle.net/74s35/3/注意:只有一些css属性触发双击行为,例如display:none; 但不是背景:红色; 或文字修饰:下划线;

我发现iPhone / iPad Safari中“:hover”是不可预知的。 有时点击元素使元素“:hover”,而有时它漂移到其他元素。

就目前而言,我只是在身体上有一个“不触摸”的课程。

 <body class="yui3-skin-sam no-touch"> ... </body> 

在“.no-touch”下面有“:hover”的所有CSS规则:

 .no-touch my:hover{ color: red; } 

在页面的某个地方,我有JavaScript从身体删除非触摸类。

 if ('ontouchstart' in document) { Y.one('body').removeClass('no-touch'); } 

这看起来不太完美,但它仍然有效。

:hover在这里不是问题。 iOS的Safari遵循一个非常奇怪的规则。 它首先触发mouseovermousemove ; 如果在这些事件中有任何改变,“点击”和相关的事件不会被解雇:

iOS中的触摸事件图

似乎包含了mouseentermouseleave ,虽然它们没有在图表中指定。

如果您因这些事件而修改任何内容,点击事件不会被解雇。 这包括DOM树中更高的东西。 例如,这将防止在您的网站上使用jQuery进行单击操作:

 $(window).on('mousemove', function() { $('body').attr('rel', Math.random()); }); 

编辑:澄清,jQuery的hover事件包括mouseentermouseleave 。 这些都将防止click如果内容改变。

浏览器function检测库Modernizer包含对触摸事件的检查。

它的默认行为是将类应用于您的html元素,以检测每个要素。 然后,您可以使用这些类来设置文档的样式。

如果没有启用触摸事件Modernizr可以添加一个no-touch的类:

 <html class="no-touch"> 

然后用这个类来定义你的hover风格:

 .no-touch a:hover { /* hover styles here */ } 

您可以下载自定义的Modernizr版本,以根据需要添加尽可能less的特征检测。

以下是一些可能适用的类的示例:

 <html class="js no-touch postmessage history multiplebgs boxshadow opacity cssanimations csscolumns cssgradients csstransforms csstransitions fontface localstorage sessionstorage svg inlinesvg no-blobbuilder blob bloburls download formdata"> 

有些设备(如其他人所说的)既有触摸又有鼠标事件。 例如,Microsoft Surface有一个触摸屏,一个触控板和一个手写笔,当它hover在屏幕上方时,实际上会引起hover事件。

任何禁用:hover基于“触摸”事件的:hover的解决scheme也将影响Surface用户(以及许多其他类似的设备)。 许多新的笔记本电脑是触摸,并会响应触摸事件 – 所以禁用hover是一个非常糟糕的做法。

这是Safari中的一个错误,这种可怕的行为绝对没有理由。 我拒绝破坏非iOS浏览器,因为iOS Safari中存在一个显然已存在多年的错误。 我真的希望他们下周在iOS8上解决这个问题,但同时…

我的解决scheme

有人build议使用Modernizr,Modernizr允许你创build自己的testing。 我基本上在这里做的是'抽象'的浏览器,支持的想法:hover到Modernizrtesting,我可以使用整个我的代码没有硬编码, if (iOS)整个if (iOS)

  Modernizr.addTest('workinghover', function () { // Safari doesn't 'announce' to the world that it behaves badly with :hover // so we have to check the userAgent return navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? false : true; }); 

然后,CSS变成这样的东西

 html.workinghover .rollover:hover { // rollover css } 

只有在iOS上,此testing将失败并禁用翻转。

这种抽象的最好的部分是,如果我发现它在某个Android上打破了,或者如果它在iOS9中被修复的话,我可以修改testing。

将FastClick库添加到您的页面将导致移动设备上的所有点击事件(无论用户点击的位置)变成点击事件,因此它还应该修复移动设备上的hover问题。 我编辑你的小提琴作为一个例子: http : //jsfiddle.net/FvACN/8/ 。

只需在页面上包含fastclick.min.js库,然后通过以下命令激活:

 FastClick.attach(document.body); 

作为一个附带的好处,它也将消除令人讨厌的300毫秒onClick延迟移动设备遭受。

使用FastClick有一些小的后果,对于您的网站可能并不重要:

  1. 如果您点击页面上的某个位置,向上滚动,向下滚动,然后松开与最初放置的位置完全相同的位置,FastClick会将其解释为“点击”,即使显然不是。 至less这就是我目前使用的FastClick版本(1.0.0)的工作方式。 自该版本以来,有人可能已经解决了这个问题。
  2. FastClick删除了某人“双击”的能力。

基本上有三种情况:

  1. 用户只有一个鼠标/指针设备,可以激活:hover
  2. 用户只有一个触摸屏,并且不能激活:hover元素
  3. 用户同时拥有触摸屏和指针设备

如果只有前两种情况是可能的,用户具有指针或触摸屏,则最初接受的答案很好。 OP在4年前问这个问题时很普遍。 一些用户指出,Windows 8和Surface设备正在使第三种情况更有可能。

iOS解决scheme无法在触摸屏设备上进行hover(详见@Zenexer),但是会导致代码错误(如OP所述)。 仅对触摸屏设备禁用hover意味着您仍然需要编写触摸屏友好的替代scheme。 检测用户何时有指针和触摸屏进一步混浊的水域(如@Simon_Weaver解释)。

在这一点上,最安全的解决scheme是避免使用:hover作为用户可以与您的网站互动的唯一方式。 hover效果是指示链接或button是否可操作的好方法,但不应要求用户hover元素才能在网站上执行操作。

考虑到触摸屏的重新思考“hover”function有关替代用户体验方法的良好讨论。 答案中提供的解决scheme包括:

  • 直接操作replacehover菜单(始终可见链接)
  • 使用点击式菜单replacehover式菜单
  • 将大量hover内容移到单独的页面中

outlook未来,这可能是所有新项目的最佳解决scheme。 被接受的答案可能是第二好的解决scheme,但一定要考虑也有指针设备的设备。 小心不要消除function,当设备有触摸屏只是为了解决iOS的问题:hover黑客。

一个更好的解决scheme,没有任何JS,CSS类和视口检查:您可以使用交互媒体function(媒体查询级别4)

喜欢这个:

 @media (hover) { // properties my:hover { color: red; } } 

iOS Safari 支持它

更多关于: https : //www.jonathanfielding.com/an-introduction-to-interaction-media-features/

.css中的JQuery版本使用.no-touch .my-element:hover所有hover规则包括JQuery和以下脚本

 function removeHoverState(){ $("body").removeClass("no-touch"); } 

然后在body标签中添加class =“no-touch”ontouchstart =“removeHoverState()”

一旦ontouchstart发动所有hover状态的class级被删除

当触摸不可用时,我只创build了hover效果,而不是创build了一个处理触摸事件的系统,并为我解决了这个问题。 首先,我定义了一个对象来testing“点击”(相当于“点击”)事件。

 touchTester = { touchStarted: false ,moveLimit: 5 ,moveCount: null ,isSupported: 'ontouchend' in document ,isTap: function(event) { if (!this.isSupported) { return true; } switch (event.originalEvent.type) { case 'touchstart': this.touchStarted = true; this.moveCount = 0; return false; case 'touchmove': this.moveCount++; this.touchStarted = (this.moveCount <= this.moveLimit); return false; case 'touchend': var isTap = this.touchStarted; this.touchStarted = false; return isTap; default: return true; } } }; 

然后,在我的事件处理程序中,我执行如下操作:

 $('#nav').on('click touchstart touchmove touchend', 'ul > li > a' ,function handleClick(event) { if (!touchTester.isTap(event)) { return true; } // touch was click or touch equivalent // nromal handling goes here. }); 

感谢@Morgan程序的答案,但是我稍微修改了JS函数获得“ touchstart ”(代码来自@Timothy Perez 答案 ),但是,你需要jQuery 1.7+

  $(document).on({ 'touchstart' : function(){ //do whatever you want here } }); 

鉴于Zenexer提供的响应,不需要额外HTML标记的模式是:

 jQuery('a').on('mouseover', function(event) { event.preventDefault(); // Show and hide your drop down nav or other elem }); jQuery('a').on('click', function(event) { if (jQuery(event.target).children('.dropdown').is(':visible') { // Hide your dropdown nav here to unstick } }); 

此方法首先触发鼠标hover,点击秒。

只要看看屏幕的大小….

 @media (min-width: 550px) { .menu ul li:hover > ul { display: block; } } 

下载你想要放入的代码

 // a function to parse the user agent string; useful for // detecting lots of browsers, not just the iPad. function checkUserAgent(vs) { var pattern = new RegExp(vs, 'i'); return !!pattern.test(navigator.userAgent); } if ( checkUserAgent('iPad') ) { // iPad specific stuff here }