且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在移动浏览器上禁用悬停效果

更新时间:2021-12-01 07:47:28

我从您的问题中得知,您的悬停效果会改变您页面的内容.在这种情况下,我的建议是:

I take it from your question that your hover effect changes the content of your page. In that case, my advice is to:

  • touchstartmouseenter 上添加悬停效果.
  • 移除 mouseleavetouchmoveclick 上的悬停效果.
  • Add hover effects on touchstart and mouseenter.
  • Remove hover effects on mouseleave, touchmove and click.

或者,您可以编辑没有内容更改的页面.

Alternatively, you can edit your page that there is no content change.

为了模拟鼠标,如果用户在触摸屏(如 iPad)上触摸并释放手指,Webkit mobile 等浏览器会触发以下事件(来源:触摸和鼠标 on html5rocks.com):

In order to simulate a mouse, browsers such as Webkit mobile fire the following events if a user touches and releases a finger on touch screen (like iPad) (source: Touch And Mouse on html5rocks.com):

  1. touchstart
  2. touchmove
  3. touchend
  4. 300 毫秒延迟,浏览器确保这是单击而不是双击
  5. 鼠标悬停
  6. 鼠标输入
    • 注意:如果 mouseovermouseentermousemove 事件改变了页面内容,则以下事件为从未被解雇.
  1. touchstart
  2. touchmove
  3. touchend
  4. 300ms delay, where the browser makes sure this is a single tap, not a double tap
  5. mouseover
  6. mouseenter
    • Note: If a mouseover, mouseenter or mousemove event changes the page content, the following events are never fired.

似乎不可能简单地告诉网络浏览器跳过鼠标事件.

更糟糕的是,如果鼠标悬停事件更改了页面内容,则永远不会触发 click 事件,如 Safari Web 内容指南 - 处理事件,尤其是单指事件中的图 6.4.内容更改"究竟是什么,将取决于浏览器和版本.我发现对于 iOS 7.0,背景颜色的更改不是(或不再是?)内容更改.

What's worse, if a mouseover event changes the page content, the click event is never fired, as explained on Safari Web Content Guide - Handling Events, in particular figure 6.4 in One-Finger Events. What exactly a "content change" is, will depend on browser and version. I've found that for iOS 7.0, a change in background color is not (or no longer?) a content change.

回顾一下:

  • touchstartmouseenter 上添加悬停效果.
  • 移除 mouseleavetouchmoveclick 上的悬停效果.
  • Add hover effects on touchstart and mouseenter.
  • Remove hover effects on mouseleave, touchmove and click.

注意 touchend 上没有任何动作!

Note that there is no action on touchend!

这显然适用于鼠标事件:mouseentermouseleave(mouseovermouseout 的略微改进版本)被触发,然后添加和删除悬停.

This clearly works for mouse events: mouseenter and mouseleave (slightly improved versions of mouseover and mouseout) are fired, and add and remove the hover.

如果用户实际点击链接,悬停效果也会被移除.这确保如果用户在 Web 浏览器中按下后退按钮,它会被删除.

If the user actually clicks a link, the hover effect is also removed. This ensure that it is removed if the user presses the back button in the web browser.

这也适用于触摸事件:在 touchstart 时添加了悬停效果.它在 touchend 上'''not''' 被删除.它在 mouseenter 上再次添加,并且由于这不会导致内容更改(它已经添加),所以 click 事件也被触发,并且不需要链接就可以跟随供用户再次点击!

This also works for touch events: on touchstart the hover effect is added. It is '''not''' removed on touchend. It is added again on mouseenter, and since this causes no content changes (it was already added), the click event is also fired, and the link is followed without the need for the user to click again!

浏览器在 touchstart 事件和 click 之间的 300 毫秒延迟实际上得到了很好的利用,因为在这很短的时间内会显示悬停效果.

The 300ms delay that a browser has between a touchstart event and click is actually put in good use because the hover effect will be shown during this short time.

如果用户决定取消点击,手指的移动将照常执行.通常,这是一个问题,因为没有触发 mouseleave 事件,并且悬停效果仍然存在.值得庆幸的是,可以通过移除 touchmove 上的悬停效果轻松解决此问题.

If the user decides to cancel the click, a move of the finger will do so just as normal. Normally, this is a problem since no mouseleave event is fired, and the hover effect remains in place. Thankfully, this can easily be fixed by removing the hover effect on touchmove.

就是这样!

请注意,可以消除 300 毫秒的延迟,例如使用 FastClick 库,但这超出了这个问题的范围.

Note that it is possible to remove the 300ms delay, for example using the FastClick library, but this is out of scope for this question.

我发现以下替代方案存在以下问题:

I've found the following problems with the following alternatives:

  • 浏览器检测:极易出错.假设设备具有鼠标或触控功能,而当触控显示器激增时,两者的结合将变得越来越普遍.
  • CSS 媒体检测:我所知道的唯一纯 CSS 解决方案.仍然容易出错,并且仍然假定设备具有鼠标或触摸功能,而两者都是可能的.
  • touchend 中模拟点击事件: 这将错误地跟随链接,即使用户只想滚动或缩放,而没有实际点击链接的意图.
  • 使用变量来抑制鼠标事件:这会在 touchend 中设置一个变量,该变量用作后续鼠标事件中的 if 条件,以防止此时状态发生变化及时.变量在点击事件中被重置.请参阅此页面上的 Walter Roman 的回答.如果您真的不希望在触摸界面上产生悬停效果,这是一个不错的解决方案.不幸的是,如果 touchend 因其他原因被触发并且没有触发点击事件(例如用户滚动或缩放),并且随后尝试用鼠标跟随链接(即在具有鼠标和触摸界面的设备).
  • browser detection: Extremely prone to errors. Assumes that a device has either mouse or touch, while a combination of both will become more and more common when touch displays prolifirate.
  • CSS media detection: The only CSS-only solution I'm aware of. Still prone to errors, and still assumes that a device has either mouse or touch, while both are possible.
  • Emulate the click event in touchend: This will incorrectly follow the link, even if the user only wanted to scroll or zoom, without the intention of actually clicking the link.
  • Use a variable to suppress mouse events: This set a variable in touchend that is used as a if-condition in subsequent mouse events to prevents state changes at that point in time. The variable is reset in the click event. See Walter Roman's answer on this page. This is a decent solution if you really don't want a hover effect on touch interfaces. Unfortunately, this does not work if a touchend is fired for another reason and no click event is fired (e.g. the user scrolled or zoomed), and is subsequently trying to following the link with a mouse (i.e on a device with both mouse and touch interface).
  • http://jsfiddle.net/macfreek/24Z5M/. Test the above solution for yourself in this sandbox.
  • http://www.macfreek.nl/memory/Touch_and_mouse_with_hover_effects_in_a_web_browser. This same answer, with a bit more background.
  • https://www.html5rocks.com/en/mobile/touchandmouse/. Great background article on html5rocks.com about touch and mouse in general.
  • https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html. Safari Web Content Guide - Handling Events. See in particular figure 6.4, which explains that no further events are fired after a content change during a mouseover or mousemove event.