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

Joe*_*ite 111 javascript hover touch

我正在编写一个旨在从台式机和平板电脑上使用的网站.当从桌面访问它时,我希望屏幕的可点击区域点亮:hover效果(不同的背景颜色等).使用平板电脑,没有鼠标,所以我不想要任何悬停效果.

问题是,当我在平板电脑上点击一些东西时,浏览器显然有某种"隐形鼠标光标",它移动到我点击的位置,然后将其留在那里 - 所以我刚刚点击的东西点亮了悬停效果,直到我点击其他东西.

我在使用鼠标时如何获得悬停效果,但在使用触摸屏时抑制它们?

如果有人想提出建议,我不想使用用户代理嗅探.同样的设备可能同时具有触摸屏和鼠标(今天可能不常见,但将来会更加如此).我对该设备不感兴趣,我对它目前的使用方式感兴趣:鼠标或触摸屏.

我已经尝试挂钩touchstart,touchmovetouchend事件,并呼吁preventDefault()对所有的人,这确实抑制"隐形鼠标"的一些时间; 但是如果我在两个不同的元素之间来回快速点击,经过几次点击它就会开始移动"鼠标光标"并点亮悬停效果 - 这就像我preventDefault并不总是很荣幸.除非必要,否则我不会厌倦你的细节 - 我甚至不确定这是正确的方法; 如果有人有更简单的解决方案,我会全力以赴.


编辑:这可以用沼泽标准的CSS :hover重现,但这里有一个快速的repro供参考.

<style>
  .box { border: 1px solid black; width: 150px; height: 150px; }
  .box:hover { background: blue; }
</style>
<div class="box"></div>
<div class="box"></div>
Run Code Online (Sandbox Code Playgroud)

如果你鼠标悬停在其中任何一个框上,它将获得我想要的蓝色背景.但是如果你点击其中任何一个盒子,它也会得到一个蓝色背景,这是我试图阻止的事情.

我还在这里发布了一个示例,它可以完成上述操作并且还可以挂钩jQuery的鼠标事件.您可以使用它来查看点击事件也会触发mouseenter,mousemove以及mouseleave.

Mac*_*eek 83

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

  • 添加悬停效果touchstartmouseenter.
  • 删除悬停效果mouseleave,touchmoveclick.

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

背景

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

  1. touchstart
  2. touchmove
  3. touchend
  4. 300毫秒的延迟,浏览器确保这是一个单击,而不是双击
  5. mouseover
  6. mouseenter
    • :如果一个mouseover,mouseentermousemove事件改变页面的内容,以下事件从未被触发.
  7. mousemove
  8. mousedown
  9. mouseup
  10. click

似乎不能简单地告诉webbrowser跳过鼠标事件.

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

解决方案解释

回顾一下:

  • 添加悬停效果touchstartmouseenter.
  • 删除悬停效果mouseleave,touchmoveclick.

请注意,没有任何操作touchend!

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

如果用户实际上click是链接,则也会删除悬停效果.这可确保在用户按下Web浏览器中的后退按钮时将其删除.

这也适用于触摸事件:在touchstart上添加了悬停效果.在touchend上没有被删除.它再次添加mouseenter,因为这不会导致内容更改(它已经添加),click事件也会被触发,并且跟踪链接而无需用户再次单击!

浏览器在touchstart事件之间延迟300ms 并且click实际上被充分利用,因为悬停效果将在这么短的时间内显示.

如果用户决定取消点击,则手指的移动将正常进行.通常,这是一个问题,因为没有mouseleave事件被触发,并且悬停效果仍然存在.值得庆幸的是,通过删除悬停效果可以很容易地解决这个问题touchmove.

而已!

请注意,可以删除300ms延迟,例如使用FastClick库,但这超出了此问题的范围.

替代方案

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

  • 浏览器检测:极易出错.假设设备具有鼠标或触摸功能,而当触摸显示器增加时,两者的组合将变得越来越常见.
  • CSS媒体检测:我唯一知道的CSS解决方案.仍然容易出错,并且仍然认为设备有鼠标或触摸,而两者都是可能的.
  • 模拟点击事件touchend:这将错误地跟随链接,即使用户只想滚动或缩放,而无意实际点击链接.
  • 使用变量来抑制鼠标事件:这将设置一个变量,touchend在后续鼠标事件中用作if条件,以防止在该时间点发生状态更改.该变量在click事件中重置.请参阅Walter Roman在此页面上的回答.如果您真的不希望在触摸界面上悬停效果,这是一个不错的解决方案.不幸的是,如果touchend由于其他原因而触发并且没有触发任何点击事件(例如用户滚动或缩放),并且随后尝试使用鼠标跟踪链接(即在具有鼠标和触摸界面的设备上),则此功能不起作用).

进一步阅读


nnn*_*nnn 19

我在使用鼠标时如何获得悬停效果,但在使用触摸屏时抑制它们?

也许不要把它想象为抑制触摸屏的悬停效果,而是为鼠标事件添加悬停效果?

如果要:hover在CSS中保留效果,可以为不同的媒体指定不同的样式:

@media screen { /* hover styles here */ } 

@media handheld { /* non-hover styles here */ }
Run Code Online (Sandbox Code Playgroud)

除了不幸的是,有很多移动设备忽略了这一点,只是使用屏幕规则.幸运的是,许多较新的移动/平板电脑浏览器确实支持一些更高级的媒体查询:

@media screen and (max-width:800px) { /* non-hover styles here */ }
Run Code Online (Sandbox Code Playgroud)

因此,即使忽略"屏幕"或"手持"部分,"max-width"也会为您提供帮助.您可以假设屏幕小于800像素的任何内容都必须是平板电脑或手机,而不是使用悬停效果.对于在低分辨率设备上使用鼠标的罕见用户,他们不会看到悬停效果,但您的网站会没有问题.

进一步阅读媒体查询?网上有很多关于这个的文章 - 这里有一篇:http://www.alistapart.com/articles/return-of-the-mobile-stylesheet

如果你将悬停效果从CSS中移出并用JavaScript应用它们,那么你可以专门绑定到鼠标事件,和/或你可能只是根据屏幕大小做出一些假设,最糟糕的"问题"是一些正在使用鼠标的用户错过了悬停效果.

  • 至于媒体查询,当Windows 8出现并且PC同时具有触摸屏*和*鼠标时会发生什么?如果用户用鼠标悬停,他们会看到鼠标光标,我想要悬停效果; 如果他们点击触摸屏,我不想要悬停效果.但我还没有找到一种可靠的方法来检测触摸和鼠标之间的区别. (6认同)

Wal*_*man 9

我为最近的一个项目编写了以下JS,这是一个桌面/移动/平板电脑网站,其悬浮效果不应该出现在触摸上.

mobileNoHoverState下面的模块有一个变量preventMouseover(最初声明为false),设置为true当用户touchstart在元素上触发事件时,$target.

preventMouseover然后falsemouseover事件被触发时被设置回,这允许站点在用户同时使用他们的触摸屏和鼠标时按预期工作.

我们知道因为它们被声明的顺序而mouseover被触发.touchstartinit

var mobileNoHoverState = function() {

    var hoverClass = 'hover',
        $target = $(".foo"), 
        preventMouseover = false;

    function forTouchstart() {
        preventMouseover = true;
    }

    function forMouseover() {
        if (preventMouseover === false) {
            $(this).addClass(hoverClass);
        } else {
            preventMouseover = false;
        }
    }

    function forMouseout() {
        $(this).removeClass(hoverClass);
    }

    function init() {
        $target.on({
            touchstart  : forTouchstart,
            mouseover   : forMouseover,
            mouseout    : forMouseout
        });                
    }

    return {
        init: init
    };
}();
Run Code Online (Sandbox Code Playgroud)

然后,该模块进一步实例化:

mobileNoHoverState.init();
Run Code Online (Sandbox Code Playgroud)


Bna*_*aya 5

我的解决方案是将hover-active css类添加到HTML标记中,并在所有CSS选择器的开头使用它:hover并在第一个touchstart事件中删除该类.

http://codepen.io/Bnaya/pen/EoJlb

JS:

(function () {
    'use strict';

    if (!('addEventListener' in window)) {
        return;
    }

    var htmlElement = document.querySelector('html');

    function touchStart () {
        document.querySelector('html').classList.remove('hover-active');

        htmlElement.removeEventListener('touchstart', touchStart);
    }

    htmlElement.addEventListener('touchstart', touchStart);
}());
Run Code Online (Sandbox Code Playgroud)

HTML:

<html class="hover-active">
Run Code Online (Sandbox Code Playgroud)

CSS:

.hover-active .mybutton:hover {
    box-shadow: 1px 1px 1px #000;
}
Run Code Online (Sandbox Code Playgroud)


fli*_*tux 5

我自己真的想要一个纯粹的css解决方案,因为在我的所有观点周围散布一个重量级的JavaScript解决方案似乎是一个令人不快的选择.最后找到@ media.hover查询,它可以检测"主输入机制是否允许用户将鼠标悬停在元素上".这避免了触摸设备,其中"悬停"更多地是模拟动作而不是输入设备的直接能力.

例如,如果我有一个链接:

<a href="/" class="link">Home</a>
Run Code Online (Sandbox Code Playgroud)

然后我可以安全地设置它的样式,只有:hover当设备轻松支持它时css:

@media (hover: hover) {
  .link:hover { /* hover styles */ }
}
Run Code Online (Sandbox Code Playgroud)

虽然大多数现代浏览器都支持交互媒体功能查询,但某些流行的浏览器(如IE和Firefox)却不支持.在我的情况下,这很好用,因为我只打算在桌面上支持Chrome,在移动设备上支持Chrome和Safari.


小智 0

查看您的 CSS 可能会有所帮助,因为这听起来是一个相当奇怪的问题。但无论如何,如果它发生并且其他一切都很好,您可以尝试将悬停效果转移到 javascript(您也可以使用 jquery)。简单地说,绑定到 mouseover 或更好的 mouseenter 事件,并在事件触发时点亮您的元素。

在这里查看最后一个示例: http: //api.jquery.com/mouseover/,您可以使用类似的东西来记录事件触发时的情况并从那里获取它!