是否有可能强迫忽略: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遵循一个非常奇怪的规则。 它首先触发mouseover
和mousemove
; 如果在这些事件中有任何改变,“点击”和相关的事件不会被解雇:
似乎包含了mouseenter
和mouseleave
,虽然它们没有在图表中指定。
如果您因这些事件而修改任何内容,点击事件不会被解雇。 这包括DOM树中更高的东西。 例如,这将防止在您的网站上使用jQuery进行单击操作:
$(window).on('mousemove', function() { $('body').attr('rel', Math.random()); });
编辑:澄清,jQuery的hover
事件包括mouseenter
和mouseleave
。 这些都将防止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有一些小的后果,对于您的网站可能并不重要:
- 如果您点击页面上的某个位置,向上滚动,向下滚动,然后松开与最初放置的位置完全相同的位置,FastClick会将其解释为“点击”,即使显然不是。 至less这就是我目前使用的FastClick版本(1.0.0)的工作方式。 自该版本以来,有人可能已经解决了这个问题。
- FastClick删除了某人“双击”的能力。
基本上有三种情况:
- 用户只有一个鼠标/指针设备,可以激活
:hover
- 用户只有一个触摸屏,并且不能激活
:hover
元素 - 用户同时拥有触摸屏和指针设备
如果只有前两种情况是可能的,用户具有指针或触摸屏,则最初接受的答案很好。 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 }