是否可以强制忽略 iPhone/iPad 用户的 :hover 伪类?
我的网站上有一些用 :hover
扩展的 css 菜单(没有 js),
这在 iDevices 上以半损坏的方式工作,例如点击将激活 :hover
> 规则并展开菜单,但点击其他位置并不会删除 :hover
。此外,如果元素内有一个被 :hover
编辑的链接,您必须点击两次才能激活该链接(第一次点击触发 :hover
,第二次点击触发链接)。
通过绑定 touchstart
事件,我已经能够在 iPhone 上正常工作。
问题是,有时移动 safari 仍然选择从我的 touchstart
事件的 css 而不是触发 :hover
规则!
我知道这是问题所在,因为当我在 css 中手动禁用所有 :hover
规则时,移动 safari 工作得很好(但常规浏览器显然不再这样了)。
当用户在移动 safari 上时,有没有办法动态“取消”某些元素的 :hover
规则?
在此处查看并比较 iOS 行为:http://jsfiddle.net/74s35/3/ 注意:只有某些 css 属性会触发双击行为,例如 display:none;但不是背景:红色;或文字装饰:下划线;
I have some css menus on my site that expand with :hover
(without js)
This works in a semi-broken way on iDevices, for example a tap will activate the :hover
rule and expand the menu, but then tapping elsewhere doesn't remove the :hover
. Also if there is a link inside the element that is :hover
'ed, you have to tap twice to activate the link (first tap triggers :hover
, second tap triggers link).
I've been able to make things work nicely on iphone by binding the touchstart
event.
The problem is that sometimes mobile safari still chooses to trigger the :hover
rule from the css instead of my touchstart
events!
I know this is the problem because when I disable all the :hover
rules manually in the css, mobile safari works great (but regular browsers obviously don't anymore).
Is there a way to dynamically "cancel" :hover
rules for certain elements when the user is on mobile safari?
See and compare iOS behavior here: http://jsfiddle.net/74s35/3/
Note: that only some css properties trigger the two-click behavior, e.g. display:none; but not background: red; or text-decoration: underline;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
我发现“:hover”在 iPhone/iPad Safari 中是不可预测的。有时点击元素会使该元素“:悬停”,而有时它会漂移到其他元素。
目前,我只在身体上上“无接触”课程。
并将所有 CSS 规则与“:hover”放在“.no-touch”下面:
在页面的某个位置,我有 javascript 从正文中删除 no-touch 类。
这看起来并不完美,但无论如何它都有效。
I found that ":hover" is unpredictable in iPhone/iPad Safari. Sometimes tap on element make that element ":hover", while sometimes it drifts to other elements.
For the time being, I just have a "no-touch" class at body.
And have all CSS rules with ":hover" below ".no-touch":
Somewhere in the page, I have javascript to remove no-touch class from body.
This doesn't look perfect, but it works anyway.
:hover
不是这里的问题。 iOS 版 Safari 遵循一个非常奇怪的规则。它首先触发mouseover
和mousemove
;如果在这些事件期间发生任何更改,“单击”和相关事件不会被触发:mouseenter
和mouseleave
似乎包含在内,尽管图表中未指定它们。如果您因这些事件而修改任何内容,则不会触发单击事件。这包括 DOM 树中更高层的东西。例如,这将阻止使用 jQuery 在您的网站上进行单击:
编辑:为了澄清起见,jQuery 的
hover
事件包括mouseenter
和mouseleave
。如果内容发生更改,这些都会阻止点击
。:hover
isn't the issue here. Safari for iOS follows a very odd rule. It firesmouseover
andmousemove
first; if anything is changed during these events, 'click' and related events don't get fired:mouseenter
andmouseleave
appear to be included, though they're not specified in the chart.If you modify anything as a result of these events, click events won't get fired. That includes something higher up in the DOM tree. For example, this will prevent single clicks from working on your website with jQuery:
Edit: For clarification, jQuery's
hover
event includesmouseenter
andmouseleave
. These will both preventclick
if content is changed.更好的解决方案,无需任何 JS、CSS 类和视口检查:您可以使用交互媒体功能 (媒体查询级别 4)
像这样:
iOS Safari 支持
更多关于:
https://www.jonathanfielding.com/an-introduction-to-交互媒体功能/
A better solution, without any JS, css class and viewport check: you can use Interaction Media Features (Media Queries Level 4)
Like this:
iOS Safari supports it
More about:
https://www.jonathanfielding.com/an-introduction-to-interaction-media-features/
浏览器功能检测库Modernizer包括对触摸事件的检查。
它的默认行为是将类应用于检测到的每个功能的 html 元素。然后,您可以使用这些类来设计文档的样式。
如果未启用触摸事件,Modernizr 可以添加一个
no-touch
类:然后使用该类调整您的悬停样式:
您可以 下载自定义 Modernizr 版本以包含您需要的尽可能少或任意数量的功能检测。
以下是一些可能应用的类的示例:
The browser feature detection library Modernizer includes a check for touch events.
It’s default behavior is to apply classes to your html element for each feature being detected. You can then use these classes to style your document.
If touch events are not enabled Modernizr can add a class of
no-touch
:And then scope your hover styles with this class:
You can download a custom Modernizr build to include as few or as many feature detections as you need.
Here's an example of some classes that may be applied:
有些设备(正如其他人所说)同时具有触摸和鼠标事件。例如,Microsoft Surface 有一个触摸屏、一个触控板和一个手写笔,当它悬停在屏幕上方时,实际上会引发悬停事件。
任何基于“触摸”事件的存在禁用
:hover
的解决方案也会影响 Surface 用户(以及许多其他类似设备)。许多新的笔记本电脑都是触摸式的,并且会响应触摸事件 - 因此禁用悬停是一种非常糟糕的做法。这是 Safari 中的一个错误,这种可怕的行为绝对没有理由。我拒绝破坏非 iOS 浏览器,因为 iOS Safari 中的一个错误显然已经存在多年了。我真的希望他们下周在 iOS8 上修复这个问题,但与此同时......
我的解决方案:
有些人已经建议使用 Modernizr,那么 Modernizr 允许您创建自己的测试。我在这里基本上所做的是将支持
:hover
的浏览器的想法“抽象”到 Modernizr 测试中,我可以在整个代码中使用该测试,而无需硬编码if (iOS)
贯穿始终。然后CSS变成这样的东西
只有在iOS上这个测试才会失败并禁用翻转。
这种抽象最好的部分是,如果我发现它在某个 Android 上出现问题或者它在 iOS9 中得到修复,那么我可以修改测试。
Some devices (as others have said) have both touch and mouse events. The Microsoft Surface for example has a touch screen, a trackpad AND a stylus which actually raises hover events when it is hovered above the screen.
Any solution that disables
:hover
based on the presence of 'touch' events will also affect Surface users (and many other similar devices). Many new laptops are touch and will respond to touch events - so disabling hovering is a really bad practice.This is a bug in Safari, there's absolutely no justification for this terrible behavior. I refuse to sabotage non iOS browsers because of a bug in iOS Safari which has apparently been there for years. I really hope they fix this for iOS8 next week but in the meantime....
My solution:
Some have suggested using Modernizr already, well Modernizr allows you to create your own tests. What I'm basically doing here is 'abstracting' the idea of a browser that supports
:hover
into a Modernizr test that I can use throughout my code without hardcodingif (iOS)
throughout.Then the css becomes something like this
Only on iOS will this test fail and disable rollover.
The best part of such abstraction is that if I find it breaks on a certain android or if it's fixed in iOS9 then I can just modify the test.
将 FastClick 库 添加到您的页面将导致移动设备上的所有点击都将转化为点击事件(无论用户在何处点击) ),因此它还应该解决移动设备上的悬停问题。我编辑了您的小提琴作为示例:http://jsfiddle.net/FvACN/8/。
只需在页面上包含 fastclick.min.js 库,并通过以下方式激活:
作为一个附带好处,它还将消除移动设备所遭受的烦人的 300 毫秒 onClick 延迟。
使用 FastClick 会产生一些小后果,这些后果对您的网站可能很重要,也可能无关紧要:
Adding the FastClick library to your page will cause all taps on a mobile device to be turned into click events (regardless of where the user clicks), so it should also fix the hover issue on mobile devices. I edited your fiddle as an example: http://jsfiddle.net/FvACN/8/.
Just include the fastclick.min.js lib on your page, and activate via:
As a side benefit, it will also remove the annoying 300ms onClick delay that mobile devices suffer from.
There are a couple of minor consequences to using FastClick that may or may not matter for your site:
基本上存在三种情况:
:hover
:hover
elements如果只有前两种情况可能,即用户拥有其中之一<,则最初接受的答案效果很好/em> 指针或触摸屏。 OP 在 4 年前提出这个问题时,这种情况很常见。一些用户指出,Windows 8 和 Surface 设备使第三种情况更有可能发生。
iOS 对于无法悬停在触摸屏设备上的问题的解决方案(如 @Zenexer 所详述)很聪明,但可能会导致简单的代码行为不当(如 OP 所指出的)。仅对触摸屏设备禁用悬停意味着您仍然需要编写触摸屏友好的替代方案。检测用户何时同时拥有指针和触摸屏会使情况进一步混乱(正如 @Simon_Weaver 所解释的)。
此时,最安全的解决方案是避免使用
:hover
作为用户与您的网站交互的唯一方式。悬停效果是指示链接或按钮可操作的好方法,但不应要求用户悬停元素来在您的网站上执行操作。重新考虑触摸屏的“悬停”功能 对替代用户体验方法进行了很好的讨论。那里的答案提供的解决方案包括:
展望未来,这可能是所有新项目的最佳解决方案。接受的答案可能是第二佳解决方案,但请务必考虑也具有指针设备的设备。当设备具有触摸屏时,请注意不要仅仅为了解决 iOS 的
:hover
黑客攻击而消除功能。There are basically three scenarios:
:hover
:hover
elementsThe originally accepted answer works great if only the first two scenarios are possible, where a user has either pointer or touchscreen. This was common when the OP asked the question 4 years ago. Several users have pointed out that Windows 8 and Surface devices are making the third scenario more likely.
The iOS solution to the problem of not being able to hover on touchscreen devices (as detailed by @Zenexer) is clever, but can cause straightforward code to misbehave (as noted by the OP). Disabling hover only for touchscreen devices means that you will still need to code a touchscreen friendly alternative. Detecting when a user has both pointer and touchscreen further muddies the waters (as explained by @Simon_Weaver).
At this point, the safest solution is to avoid using
:hover
as the only way a user can interact with your website. Hover effects are a good way of indicating that a link or button is actionable, but a user should not be required to hover an element to perform an action on your website.Re-thinking “hover” functionality with touchscreens in mind has a good discussion about alternative UX approaches. The solutions provided by the answer there include:
Moving forward, this will probably be the best solution for all new projects. The accepted answer is probably the second best solution, but be sure to account for devices that also have pointer devices. Be careful not to eliminate functionality when a device has a touchscreen just to work around iOS's
:hover
hack.JQuery 版本
在你的 .css 使用中
.no-touch .my-element:hover
适用于您所有的悬停规则
包含 JQuery 和以下脚本
然后在 body 标记中添加
class="no-touch" ontouchstart="removeHoverState()"
一旦 ontouchstart 触发,所有悬停状态的类就会被删除
The JQuery version
in your .css use
.no-touch .my-element:hover
for all your hover rules
include JQuery and the following script
Then in body tag add
class="no-touch" ontouchstart="removeHoverState()"
as soon as the ontouchstart fires the class for all hover states is removed
我同意禁用悬停触摸是可行的方法。
但是,为了省去重写 css 的麻烦,只需将任何
:hover
项包装在@supports not (-webkit-overflow-scrolling: touch) {}
中I agree disabling hover for touch is the way to go.
However, to save yourself the trouble of re-writing your css, just wrap any
:hover
items in@supports not (-webkit-overflow-scrolling: touch) {}
我创建了一个处理触摸事件的系统,而不是仅在触摸不可用时具有悬停效果,这为我解决了问题。首先,我定义了一个用于测试“tap”(相当于“click”)事件的对象。
然后,在我的事件处理程序中,我执行如下操作:
Instead of only having hover effects when touch is not available I created a system for handling touch events and that has solved the problem for me. First, I defined an object for testing for "tap" (equivalent to "click") events.
Then, in my event handler I do something like the following:
感谢@Morgan Cheng 的回答,但是我稍微修改了 JS 函数来获取“touchstart”(代码取自@Timothy Perez answer),但是,您需要 jQuery 1.7+
Thanks @Morgan Cheng for the answer, however I've slightly modified the JS function for getting the "touchstart" (code taken from @Timothy Perez answer), though, you need jQuery 1.7+ for this
鉴于 Zenexer 提供的响应,不需要额外 HTML 标签的模式是:
此方法首先触发鼠标悬停,然后单击。
Given the response provided by Zenexer, a pattern that requires no additional HTML tags is:
This method fires off the mouseover first, the click second.
对于那些在 iOS Safari 上禁用
:hover
事件的常见用例,最简单的方法是对:hover
事件使用最小宽度媒体查询,该查询保持在您要避免使用的设备的屏幕宽度。例子:For those with common use case of disabling
:hover
events on iOS Safari, the simplest way is to use a min-width media query for your:hover
events which stays above the screen width of the devices you are avoiding. Example:对于仍在寻找解决方案的人,如果上述方法都不起作用,
请尝试一下,
此悬停伪代码仅适用于带有指针的设备,并且在仅具有 .active 类的触摸设备上正常工作。
For someone still looking for a solution if none of the above worked,
Try this,
This hover pseudo will only be applied for devices with pointers and works normal on touch devices with just .active classes.
直接看屏幕大小就可以了....
Just look at the screen size....
这是您想要将其放入的代码
heres the code you'll want to place it in