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


141

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

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

因此,如何:hover在声明触摸设备后立即删除/忽略所有CSS 声明(而不必知道每个CSS )?



1
我通过php解决方案解决了这个问题,在该解决方案中,我发现查看设备是否可移动,并使用正确的样式表并基于此进行各种更改。但是,这并不能回答您的问题。您可能会使用@media查询,但这不能保证在手机和平​​板电脑具有全高清分辨率时都无法使用。
TomFirth 2014年

Answers:


171

tl; dr使用此:https : //jsfiddle.net/57tmy8j3/

如果您对为什么或还有其他选择感兴趣,请继续阅读。

Quick'n'dirty-使用JS删除:hover样式

您可以删除所有包含:hover使用Javascript 的CSS规则。这样做的优点是不必接触CSS,并且即使与较旧的浏览器也兼容。

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

if (hasTouch()) { // remove all the :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和iPad Pro 等混合鼠标和触摸设备上徘徊,这会伤及UX。

仅CSS-使用媒体查询

将所有:hover规则放在一个@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规则。两者都是与混合的鼠标和触摸设备不兼容

最强大-通过JS检测触摸并添加CSS:hover规则

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

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

hasHover类可以使用加入hasTouch()从第一个例子:

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

但是,对于混合触摸设备来说,这将具有与先前示例相同的缺点,这将我们带到了最终解决方案。每当移动鼠标光标时启用悬停效果,每当检测到触摸时禁用悬停效果。

function watchForHover() {
  // lastTouchTime is used for ignoring emulated mousemove events
  let lastTouchTime = 0

  function enableHover() {
    if (new Date() - lastTouchTime < 500) return
    document.body.classList.add('hasHover')
  }

  function disableHover() {
    document.body.classList.remove('hasHover')
  }

  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/57tmy8j3/
旧版(用于旧浏览器):https : //jsfiddle.net/dkz17jc5/19/


谢谢!只是一个评论:最好先检查是否 document.styleSheets存在而不是使用try/catch
Simon Ferndriger

1
我已经使用过try/catch,以防出现一些奇怪的错误,这可能会使脚本崩溃,例如deleteRule由于同源策略或对IE的不稳定支持而无法正常工作(已编辑注释以反映该情况)。但是,是的,在大多数情况下,只需简单的检查就足够了。
刀片

1
值得一提的是,包括Firefox在内的桌面浏览器不会导致“ notouch”。他们报告了解触摸事件。
哈里B

3
此解决方案不适用于将鼠标悬停但不适用于触摸事件的混合设备
nbar

2
@Haneev在大多数情况下是正确的,尽管不适用于您的特定情况。使您的规则有效将增加代码的复杂性,这将使答案更难以理解。我建议拆分规则或使用第二种解决方案,无论如何,这种解决方案更加可靠。但是,如果可以在不使第一个解决方案变得过于复杂的情况下对其进行改进,则非常欢迎您提出修改建议。
刀片

43

指针适应救援!

由于这已经有一段时间没有涉及了,因此您可以使用:

a:link {
   color: red;
}

a:hover {
   color:blue;
}

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

在台式机浏览器和手机浏览器中均可看到此演示。由现代触摸设备支持。

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


谢谢,这将很方便!但是,我在移动模式下使用Chrome进行了试用,但无法正常工作-当我“轻按”它时,它还是变蓝了……
Simon Ferndriger

1
@SimonFerndriger那只是Chrome devtools的限制。尝试在实际的仅触摸式设备中打开链接。
Jason T Featheringham

1
在iPad Chrome / Safari和OS X Chrome / Safari上完美兼容。谢谢!最后,您需要一个优雅的解决方案来解决如此小的视觉问题。
rakaloof

3
我只是在运行iOS 11的实际iPhone 6S上尝试了此操作,链接变为蓝色。
卢卡斯·彼得

1
还可以在运行Android 8.1.0和Chrome 68.0.3440.91的Nexus 5X上进行尝试。链接变为蓝色。
特雷文·艾利

12

我遇到了同样的问题(以三星移动浏览器为例),因此我偶然发现了这个问题。

多亏了Calsal的回答,我发现了一些我认为可以排除几乎所有台式机浏览器的东西,因为它似乎被我尝试过的移动浏览器所识别(请参阅编译表的屏幕截图:CSS指针功能检测表)。

MDN Web文档指出

指针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;
  }
}

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

更新:截至2018年8月23日撰写此更新,并由@DmitriPavlutin指出,此技术似乎不再适用于Firefox桌面。


感谢@DmitriPavlutin,根据表格(编译时),它应该可以,但是我可以再看一遍。
ProgrammerPer

@DmitriPavlutin您确实是正确的。将更新答案
ProgrammerPer

1
您的意思是如果与专用触摸设备一起使用,则在Firefox桌面上不起作用?我尝试过的一切都可以很好地工作。
FuzzeeLowgeek

@FuzzeeLowgeek听起来不错!我上次检查的时间是2018-08-23,所以如果您可以确定确认这一点,也许我可以再次更新答案?
程序员每

9

根据Jason的回答,我们只能使用纯CSS媒体查询来处理不支持悬停的设备。我们也只能使用来解决支持悬停的设备,例如moogal在类似问题中的 回答@media not all and (hover: none)。看起来很奇怪,但是有效。

我用它制作了一个Sass mixin,以便于使用:

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

更新2019-05-15:我推荐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 */
}

我喜欢mixin,这是我将悬停mixin仅用于支持它的目标设备的方式:

@mixin on-hover {
    @media (hover: hover) and (pointer: fine) {
        &:hover {
            @content;
        }
    }
}

button {
    @include on-hover {
        color: blue;
    }
}

那根本不起作用。您有悬停:媒体查询中没有悬停支持的mixin吗?您需要指针:根据此处的其他答案进行粗略处理。
艾伦·尼恩惠斯

您是否尝试过或者只是说它看起来很奇怪而不能使用?这就是为什么我写“它看起来很奇怪”的原因。它确实对我有用,没有指针:粗略。
Calsal

我在OnePlus 5T(在Chrome和Firefix中)上使用CSS方法的结果不一致。这在iOS上运行良好,但我无法在OnePlus上运行。我使用任意指针和任意悬停
Zeth,

6

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

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

  1. 如果您能够使用Internet胶带语言(例如PHP或Ruby),则可以检查请求页面的设备的用户字符串,并仅提供相同的内容,但使用<link rel="mobile.css" />常规样式代替。

用户字符串具有有关浏览器,渲染器,操作系统等的标识信息。由您决定哪些设备是“触摸”设备还是非触摸设备。您可能可以在某处找到此信息,并将其映射到系统中。

答:如果允许您忽略旧的浏览器,则只需向正常的非移动CSS添加一个规则,即: EDIT:Erk。经过一些实验后,我发现以下规则除了禁用美学效果外,还禁用了跟随webkit-browsers中的链接的功能-参见http://jsfiddle.net/3nkcdeao/
这样,您将拥有与我在此处显示的内容相比,对于如何修改移动案例的规则更具选择性,但这可能是一个有用的起点:

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

附带说明,当前禁用父级上的指针事件,然后在子级上显式启用它们,如果输入子级元素,则当前对父级的任何悬停效果都会再次变为活动状态:hover
看到 http://jsfiddle.net/38Lookhp/5/

B.如果您支持旧版Web渲染器,则您将需要做更多的工作来删除期间设置特殊样式的任何规则:hover。为了节省每个人的时间,您可能只想构建一个自动复制+ sed ing命令,您可以在标准样式表上运行该命令来创建移动版本。这样一来,您就可以编写/更新标准代码并清除:hover用于移动版本页面的所有样式规则。

  1. (I)或者,仅使您的用户知道您除了website.com之外,还拥有一个用于移动设备的m.website.com。尽管子域化是最常见的方式,但是您也可以对给定的URL进行其他一些可预测的修改,以允许移动用户访问修改后的页面。在那个阶段,您需要确保他们不必每次导航到网站的另一部分时都修改URL。

再次在这里,您可以只向样式表添加一两个额外的规则,也可以使用sed或类似的实用程序强制执行一些稍微复杂的事情。可能最容易应用:不应用于样式规则,例如div:not(.disruptive):hover {...不添加样式class="disruptive"元素,而是添加元素以使用js或服务器语言为移动用户做烦人的事情,而不用烦恼CSS。

  1. (II)实际上,您可以将前两个结合起来(如果您怀疑用户已经漫游到错误的页面版本),则可以建议他们切换到/退出移动类型的显示屏,或者只是在某个位置有链接允许用户来回翻转。正如已经指出的那样,@ media查询也可以用来确定正在访问的内容。

  2. (III)如果您知道什么是“触摸”设备,而哪些不是,则准备使用jQuery解决方案,那么您可能会发现CSS悬停在触摸屏设备上不会被忽略是有帮助的。


pointer-events- 棒极了!这正是我想要的,非常感谢!
Simon Ferndriger 2014年

1
@SimonFerndriger好吧,我希望以后对您有所帮助。请务必注意到目前为止的警告,<a>在下的链接可能无法访问pointer-events:none。运气好的话,这将在以后改变–否则CSS 3.x或4.0+将具有pointer-events:navigation-only或类似的性能。
SeldomNeedy 2014年

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)。


这确实可以解决问题。我以前从未听说过。应该在哪个浏览器版本中工作?
Simon Ferndriger '16


很好...它没有广泛的浏览器支持。
贾科莫·派塔

这很酷!谢谢您这样方便的解决方案。我希望它将被添加到W3C标准中。
GProst '17年

很高兴我能为您提供帮助^^
Marouen Mhiri'5

5

您可以使用Modernizr JS(另请参见此StackOverflow答案),或制作自定义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;
}

@blade也建议这样做-但是,使用html标签代替body标签可能会使阅读效果更好。这实际上是我当前正在使用的解决方案。还是很感谢你。
西蒙·费恩德里格

1

这对我很有帮助:链接

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");
                    }
                }
            }
        }
    }
}

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>

资源

Ps但是我们应该记住,市场上有越来越多的触摸设备,它们同时支持鼠标输入。


0

这可能不是一个完美的解决方案(与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");
});

1
一个问题实际上是,当在触摸设备上单击某些内容时,它也是.mousemove()。
lars在upstruct

1
您可能会不停地触发此事件,从而对性能产生影响。如果这样的工作,应该比你更好的使用$('body').one.('mousemove', ...)
西蒙Ferndriger

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;
}

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;
  }
}

0

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

光标:POINTER;到CURSOR:默认;

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

这对我有用。


-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/


2
在2019年,您不需要使用jQuery-WebAPI非常强大并且支持所有主要功能。
acme,

是的... 2019年的jQuery吗?闪存怎么样?呵呵呵
remed.io
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.