如何删除/忽略:在触摸设备上悬停css样式

时间:2014-05-27 09:06:00

标签: html css hover touch

如果用户通过触摸设备访问我们的网站,我想忽略所有:hover CSS声明。因为:hover CSS没有意义,如果平板电脑在点击/点按时触发它,它甚至可能会令人不安,因为它可能会坚持直到元素失去焦点。说实话,我不知道为什么触摸设备首先需要触发:hover - 但这是现实,所以这个问题也是现实。

a:hover {
   color:blue;
   border-color:green;
   // etc. > ignore all at once for touch devices
}

那么,如何(如何)在声明触摸设备后立即删除/忽略所有CSS :hover声明(无需了解每一个)?

17 个答案:

答案 0 :(得分:112)

此问题有多种解决方案。

Quick'n'dirty - 删除:使用JS

悬停样式

您可以使用Javascript删除包含:hover的所有CSS规则。这样做的好处是无需触摸CSS,即使使用旧版浏览器也能兼容。

function hasTouch() {
    return 'ontouchstart' in document.documentElement
           || navigator.maxTouchPoints > 0
           || navigator.msMaxTouchPoints > 0;
}

if (hasTouch()) { // remove all :hover stylesheets
    try { // prevent exception on browsers not supporting DOM styleSheets properly
        for (var si in document.styleSheets) {
            var styleSheet = document.styleSheets[si];
            if (!styleSheet.rules) continue;

            for (var ri = styleSheet.rules.length - 1; ri >= 0; ri--) {
                if (!styleSheet.rules[ri].selectorText) continue;

                if (styleSheet.rules[ri].selectorText.match(':hover')) {
                    styleSheet.deleteRule(ri);
                }
            }
        }
    } catch (ex) {}
}

限制:样式表必须托管在相同域(这意味着没有CDN)。禁用像Surface这样的混合mouse & touch devices上的悬停,这会伤害用户体验。

仅限CSS - 使用媒体查询

将所有:悬停规则放在@media块中:

@media (hover: hover) {
    a:hover { color: blue; }
}

或者,覆盖所有悬停规则(与旧浏览器兼容):

a:hover { color: blue; }

@media (hover: none) {
    a:hover { color: inherit; }
}

限制:在使用WebView时,仅适用于iOS 9.0 +,Chrome for Android或Android 5.0+。 hover: hover打破旧浏览器上的悬停效果,hover: none需要覆盖之前定义的所有CSS规则。两者都与混合鼠标&触控设备

最强大 - 使用特殊的CSS类并通过JS检测触摸

此方法需要在body.hasHover之前添加所有悬停规则。 (或您选择的班级名称)

body.hasHover a:hover { color: blue; }

可以使用第一个示例中的hasHover添加hasTouch()类:

if (!hasTouch()) {
    document.body.className += ' hasHover';
}

然而,这与前面的例子中的混合触摸设备存在相同的问题,这使我们得到了最终的解决方案。移动鼠标光标时启用悬停效果,每当检测到触摸时禁用悬停效果。

function watchForHover() {
    var hasHoverClass = false;
    var container = document.body;
    var lastTouchTime = 0;

    function enableHover() {
        // filter emulated events coming from touch events
        if (new Date() - lastTouchTime < 500) return;
        if (hasHoverClass) return;

        container.className += ' hasHover';
        hasHoverClass = true;
    }

    function disableHover() {
        if (!hasHoverClass) return;

        container.className = container.className.replace(' hasHover', '');
        hasHoverClass = false;
    }

    function updateLastTouchTime() {
        lastTouchTime = new Date();
    }

    document.addEventListener('touchstart', updateLastTouchTime, true);
    document.addEventListener('touchstart', disableHover, true);
    document.addEventListener('mousemove', enableHover, true);

    enableHover();
}

watchForHover();

这基本上可以在任何浏览器中工作,并根据需要启用/禁用悬停样式。在这里试试:https://jsfiddle.net/dkz17jc5/19/

答案 1 :(得分:32)

Pointer adaptation救援!

由于暂时没有触及,您可以使用:

a:link {
   color: red;
}

a:hover {
   color:blue;
}

@media (hover: none) {
   a:link {
      color: red;
   }
}

demo in both your desktop browser and your phone browser。由modern touch devices支持。

注意:请记住,由于Surface PC的主要输入(功能)是鼠标,它最终将成为蓝色链接,即使它是一个分离的(平板电脑)屏幕。浏览器将(应该)始终默认为最精确的输入功能。

答案 2 :(得分:17)

2020解决方案-仅CSS-无Javascript

media hovermedia pointer配合使用将帮助您解决此问题。在chrome Web和android mobile上测试。我知道这个老问题,但没有找到这样的解决方案。

@media (hover: hover) and (pointer: fine) {
  a:hover { color: red; }
}
<a href="#" >Some Link</a>

答案 3 :(得分:7)

我目前正在处理类似的问题。

立即出现两个选项:(1)用户字符串检查,或(2)使用不同的URL维护单独的移动页面,并让用户选择更适合他们的内容。

  1. 如果您能够使用互联网风管磁带语言(如PHP或Ruby),则可以检查请求页面的设备的用户字符串,并只提供相同的内容,但是<link rel="mobile.css" />代替正常风格。
  2. 用户字符串包含有关浏览器,渲染器,操作系统等的识别信息。您可以自行决定哪些设备是“触摸”而非非触摸。您可以在某处找到此信息并将其映射到您的系统中。

    <击>一个。如果你被允许ignore old browsers,你只需要向正常的非移动css添加一条规则,即: EDIT :Erk。在做了一些实验之后,我发现下面的规则还禁用了在webkit浏览器中跟踪链接的能力,以及仅仅导致美学效果被禁用 - 请参阅http://jsfiddle.net/3nkcdeao/因此,你必须对于你如何修改移动案例的规则比我在这里展示的更有选择性,但它可能是一个有用的起点:

    * { 
        pointer-events: none !important; /* only use !important if you have to */
    }
    

    作为旁注,如果子元素输入:hover,则禁用父项上的指针事件然后在子项上显式启用它们会导致父项上的任何悬停效果再次变为活动状态。
    请参阅http://jsfiddle.net/38Lookhp/5/

    B中。如果您支持遗留的网络渲染器,则必须在删除:hover期间设置特殊样式的任何规则时执行更多工作。为了节省每个人的时间,您可能只想构建一个自动复制+ sed命令,您可以在标准样式表上运行该命令来创建移动版本。这样您就可以编写/更新标准代码,并删除任何使用:hover用于移动版网页的样式规则。

    1. (I)或者,只需让您的用户知道除了 website.com 之外,您还拥有适用于移动设备的 m.website.com 。尽管subdomaining是最常见的方式,但您还可以对给定URL进行其他可预测的修改,以允许移动用户访问已修改的页面。在那个阶段,您需要确保他们每次导航到网站的其他部分时都不必修改URL。
    2. 再次在这里,您可以在样式表中添加一两个额外的规则,或者使用sed或类似的实用程序强制执行稍微复杂的操作。这可能是最容易应用的:不是你的样式规则,如div:not(.disruptive):hover {...,你可以将class="disruptive"添加到使用js或服务器语言为移动用户做烦人的元素,而不是使用CSS。< / p>

      1. (II)您实际上可以合并前两个(如果您怀疑用户徘徊到错误版本的页面),您可以建议他们切换到移出式显示器,或者只需要一个允许用户来回翻转的链接。如前所述,@ media查询也可能用于确定用于访问的内容。

      2. (III)如果您知道哪些设备是“触摸”而哪些设备不是“触摸”,那么您可能会发现CSS hover not being ignored on touch-screen devices有用。

答案 4 :(得分:6)

试试这个:

@media (hover:<s>on-demand</s>) {
    button:hover {
        background-color: #color-when-NOT-touch-device;
    }
}

更新:遗憾的是,W3C已从规范(https://github.com/w3c/csswg-drafts/commit/2078b46218f7462735bb0b5107c9a3e84fb4c4b1)中删除了此属性。

答案 5 :(得分:6)

我遇到了同样的问题(在我的情况下使用三星移动浏览器)因此我偶然发现了这个问题。

感谢Calsal's answer我发现了一些我认为会排除几乎所有桌面浏览器的东西,因为它似乎被我尝试过的移动浏览器识别出来(请参阅编译表中的截图:CSS pointer feature detection table )。 / p>

MDN web docs声明

  

指针CSS @media功能可用于基于应用样式   用户的主要输入机制是否是指点设备,和   如果是这样,它有多准确

我发现指针:粗略是附加表中所有桌面浏览器都不知道但同一个表中所有移动浏览器都知道的内容。这似乎是最有效的选择,因为所有其他指针关键字值都会产生不一致的结果。

因此,您可以构建一个类似Calsal的媒体查询,但稍加修改。它利用反向逻辑排除所有触摸设备。

Sass mixin:

@mixin hover-supported {    
    /* 
     * https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer 
     * coarse: The primary input mechanism includes a pointing device of limited accuracy.
     */
    @media not all and (pointer: coarse) {
        &:hover {
            @content;
        }
    }
}

a {
    color:green;
    border-color:blue;

    @include hover-supported() {
        color:blue;
        border-color:green;
    }
}

编译CSS:

a {
  color: green;
  border-color: blue;
}
@media not all and (pointer: coarse) {
  a:hover {
    color: blue;
    border-color: green;
  }
}

我在研究问题后创建的gist中也对此进行了描述。 Codepen用于实证研究。

<强>更新: 截至撰写此更新时,2018-08-23,@ DmitriPavlutin指出,这种技术似乎不再适用于Firefox桌面。

答案 6 :(得分:4)

您可以使用Modernizr JS(另请参阅此StackOverflow answer),或制作自定义JS函数:

function is_touch_device() {
 return 'ontouchstart' in window        // works on most browsers 
  || navigator.maxTouchPoints;       // works on IE10/11 and Surface
};

if ( is_touch_device() ) {
  $('html').addClass('touch');
} else {
  $('html').addClass('no-touch');
} 

在浏览器中检测触摸事件的支持,然后分配常规CSS属性,遍历html.no-touch类的元素,如下所示:

html.touch a {
    width: 480px;
}

/* FOR THE DESKTOP, SET THE HOVER STATE */
html.no-touch a:hover {
   width: auto;
   color:blue;
   border-color:green;
}

答案 7 :(得分:1)

为了使当前的答案也适用于 IE11(如果您仍然支持):

@media (hover: hover) and (pointer: fine), only screen and (-ms-high-contrast:active), (-ms-high-contrast:none) {
  a:hover { color: red; }
}
<a href="#" >Some Link</a>

答案 8 :(得分:1)

根据Jason´s answer,我们只能解决不支持使用纯css媒体查询进行悬停的设备。我们也可以只处理支持悬停的设备,例如类似问题中的moogal´s answer @media not all and (hover: none)。它看起来很奇怪,但它确实有效。

为了方便起见,我制作了一个Sass mixin:

@mixin hover-supported {
    @media not all and (hover: none) {
        &:hover {
            @content;
        }
    }
}

更新2019-05-15 :我建议this article from Medium遍历我们可以使用CSS定位的所有不同设备。基本上它是这些媒体规则的混合,将它们结合起来用于特定目标:

@media (hover: hover) {
    /* Device that can hover (desktops) */
}
@media (hover: none) {
    /* Device that can not hover with ease */
}
@media (pointer: coarse) {
    /* Device with limited pointing accuracy (touch) */
}
@media (pointer: fine) {
    /* Device with accurate pointing (desktop, stylus-based) */
}
@media (pointer: none) {
    /* Device with no pointing */
}

特定目标的示例:

@media (hover: none) and (pointer: coarse) {
    /* Smartphones and touchscreens */
}

@media (hover: hover) and (pointer: fine) {
    /* Desktops with mouse */
}

我喜欢mixins,这就是我使用它的方式:

@mixin is-touch {
    @media (hover: none) and (pointer: coarse) {
        @content;
    }
}

答案 9 :(得分:1)

这可能不是一个完美的解决方案(并且它与jQuery一起使用)但也许它是一个方向/概念可以解决这个问题:那么反过来呢?这意味着默认情况下停用:hover css状态,如果在文档的任何位置检测到mousemove事件,则激活它们。当然,如果有人停用了js,这不起作用。还有什么可以反对这样做呢?

也许是这样的:

CSS:

/* will only work if html has class "mousedetected" */
html.mousedetected a:hover {
   color:blue;
   border-color:green;
}

jQuery的:

/* adds "mousedetected" class to html element if mouse moves (which should never happen on touch-only devices shouldn’t it?) */
$("body").mousemove( function() {
    $("html").addClass("mousedetected");
});

答案 10 :(得分:1)

这也是一种可行的解决方法,但您必须通过自己的CSS并在悬停样式之前添加.no-touch课程。

使用Javascript:

if (!("ontouchstart" in document.documentElement)) {
document.documentElement.className += " no-touch";
}

CSS示例:

<style>
p span {
    display: none;
}

.no-touch p:hover span {
    display: inline;
}
</style>
<p><a href="/">Tap me</a><span>You tapped!</span></p>

Source

P.S。但我们应该记住,市场上有越来越多的触控设备,同时也支持鼠标输入。

答案 11 :(得分:0)

尝试一下(在此示例中,我使用background和background-color):

var ClickEventType = ((document.ontouchstart !== null) ? 'click' : 'touchstart');

if (ClickEventType == 'touchstart') {
            $('a').each(function() { // save original..
                var back_color = $(this).css('background-color');
                var background = $(this).css('background');
                $(this).attr('data-back_color', back_color);
                $(this).attr('data-background', background);
            });

            $('a').on('touchend', function(e) { // overwrite with original style..
                var background = $(this).attr('data-background');
                var back_color = $(this).attr('data-back_color');
                if (back_color != undefined) {
                    $(this).css({'background-color': back_color});
                }
                if (background != undefined) {
                    $(this).css({'background': background});
                }
            }).on('touchstart', function(e) { // clear added stlye="" elements..
                $(this).css({'background': '', 'background-color': ''});
            });
}

css:

a {
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

答案 12 :(得分:0)

肮脏的方式...并不优雅,但是可以拯救您的最简单的方式。

删除所有表现出悬停特征的内容。

.your-class:hover:before {
  color: blue;
  background: linear-gradient(to bottom, rgba(231,56,39,0) 0%, #aaaaaa 100%);
}

@media all and (min-width:320px) and (max-width: 960px) {
    .your-class:hover:before {
    color: black;
    background: transparent;
  }
}

答案 13 :(得分:0)

如果您的问题是当您触摸/点击android和整个div都覆盖有蓝色透明色时!然后,您只需更改

光标:POINTER; 至 光标:默认;

使用mediaQuery隐藏在手机/平板电脑中。

这对我有用。

答案 14 :(得分:0)

对我有帮助:link

function hoverTouchUnstick() {
    // Check if the device supports touch events
    if('ontouchstart' in document.documentElement) {
        // Loop through each stylesheet
        for(var sheetI = document.styleSheets.length - 1; sheetI >= 0; sheetI--) {
            var sheet = document.styleSheets[sheetI];
            // Verify if cssRules exists in sheet
            if(sheet.cssRules) {
                // Loop through each rule in sheet
                for(var ruleI = sheet.cssRules.length - 1; ruleI >= 0; ruleI--) {
                    var rule = sheet.cssRules[ruleI];
                    // Verify rule has selector text
                    if(rule.selectorText) {
                        // Replace hover psuedo-class with active psuedo-class
                        rule.selectorText = rule.selectorText.replace(":hover", ":active");
                    }
                }
            }
        }
    }
}

答案 15 :(得分:-1)

这可以通过sass / scss和带有所需断点的媒体查询来解决。

.myclass {
    background-color: blue;
    &:hover {
        @media screen and (max-width: 320px) {
            background-color: red;
        }
    }
}

答案 16 :(得分:-1)

尝试这种简单的2019 jquery解决方案,尽管已经有一段时间了;

  1. 将此插件添加到头部:

    src =“ https://code.jquery.com/ui/1.12.0/jquery-ui.min.js”

  2. 将此添加到js:

    $(“ *”)。on(“ touchend”,function(e){$(this).focus();}); //适用于所有元素

  3. 对此的一些建议变体是:

    $(“:input,:checkbox,”)。on(“ touchend”,function(e){(this).focus);}); //指定元素

    $(“ *”)。on(“ click,touchend”,function(e){$(this).focus();}); //包括点击事件

    css:正文{光标:指针; } //触摸任何地方以结束焦点

注释

  • 将插件放置在bootstrap.js之前,以免影响工具提示
  • 仅在使用Safari或Chrome的iphone XR ios 12.1.12和ipad 3 ios 9.3.5上进行了测试。

参考文献:

https://code.jquery.com/ui/

https://api.jquery.com/category/selectors/jquery-selector-extensions/