支持悬停设备的媒体查询

61
I'd like you to serve different behaviors for browsers that support hover (e.g. desktop browsers) and those that don't (e.g. touchscreen devices). Specifically, I intend to establish a hover state on browsers that support it but not on those that don't, so as to prevent mobile browsers from emulating it with extra taps, which can disrupt other interactions on the page. By not defining a hover state for these browsers, this issue is avoided.
I have researched the Interaction Media Queries feature, and it seems like it can solve the problem. I would be able to use something like this:
@media (hover: none) {
  /* behaviour for touch browsers */
}

根据CanIUse,除了IE11和Firefox外,我需要支持的所有浏览器都可以使用它。
因此,我想知道是否可以反过来做 - 由于主要的触摸设备都支持它,那么是否可以将其否定:
@media not (hover: none) {
  /* behaviour for desktop browsers */
}

然而,这似乎根本没有起作用。
我尝试做的伪代码示例:
.myelement {
  /* some styling */
  /* note: no hover state here */
}
@media(this device supports hover) {
  .myelement:hover {
    /* more styling */
  }
}

那么,有没有办法让这个工作以预期的方式运行,还是我走错了方向?


4
请勿使用“hover”媒体查询。我使用27英寸的显示器和鼠标工作,但是所有浏览器设置为“hover:none”,尽管我喜欢并且能够经常使用悬停功能。也许我的所有浏览器都设置了“hover:none”,因为我的笔记本电脑连接了外设,具有触摸屏。也许你可以尝试使用任何悬停媒体查询 https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-hover - Andreas
@Andreas 把这个变成一个答案,这样它就足够显眼了。我因为这个问题疯了。每个人都在谈论 hover,但我的两个浏览器既无法通过 pointer:fine 检测到我的鼠标,也无法接受 hover:hover。但这个提示解决了我的问题... - Thomas Urban
1
我已经制作了一个网站,您可以通过它测试您的浏览器设置,以解决此问题。 https://andreasburg.de/lenovo-browser-hover-check.html - Andreas
现在至少在2021年,您可以使用MDN文档中提到的两个关键字hover来实现悬停效果。不确定您是否正在寻找此实现方式,但希望将来有人会发现这很有用! - Hasintha Abeykoon
@Andreas,你能否在你的测试网站上添加“pointer”媒体查询的测试吗?将这两个相关查询的测试放在一个地方会更加方便。 - Joshua Fan
2
请注意,三星设备存在一个错误,它们报告(hover:hover)而不是(hover:none)!https://www.ctrl.blog/entry/css-media-hover-samsung.html - Daniel
7个回答

74
< p >< code >不应该在媒体类型(屏幕、打印、全部等)或媒体特性(悬停、指针等)前面使用< /code >< /p > < p >错误的例子:


错误的示例:

@media not (hover: none)

正确:

@media not all and (hover: none)

是的,它不直观而且很奇怪。来源(请查看评论)

因此,您不需要使用JavaScript来交替媒体查询的结果。


6
好的技巧!只是请注意,IE11似乎完全忽略了这个规则。使用另一个针对IE的hack,似乎以下内容可以工作(尽管它是解决方法的否定版本):@media not all and (hover: none), (-ms-high-contrast: none) { - Stiggler
3
在Firefox浏览器中,无论是@media (hover: none)还是否定的@media not all and (hover: none)都不起作用。这个浏览器不支持悬停 https://bugzilla.mozilla.org/show_bug.cgi?id=1035774 ,但是如果没有识别到not的主语,有没有一种方法可以编写not,使其评估为false(并且整个媒体查询评估为true)? - EoghanM
3
根据媒体查询4的规定,“not (hover: none)”并不是错误的,至少现在不是了。但令人沮丧的是,目前还没有任何浏览器支持它。请参考 https://dev59.com/vYHba4cB1Zd3GeqPLwiF#24456052 。 - BoltClock
3
为什么不使用@media (hover) {...桌面样式...}?这是个愚蠢的问题。 - basZero
2
其实我不明白为什么所有人都试图通过关键字hover而不是none来否定条件,这个条件可以直接实现。也许现在已经实施了,但在提问时还没有,详见此处 - Hasintha Abeykoon
显示剩余5条评论

20

从规范中可以看出:

none

表示主要指针系统无法悬停,或没有指针系统。例如触摸屏和使用绘图笔的屏幕。能够悬停但不方便且不是正常使用方式的指针系统也符合此值。

例如,长按触摸屏被视为悬停的情况,将匹配 hover: none。

如果您的浏览器(移动/触控)支持长按来模拟悬停,则使用 hover: none 将无效。您可以使用默认值并覆盖它(具有默认 CSS 优先级):

body {
    background: red;
}

@media (hover: hover) {
  body {
    background: blue;
  }
}

桌面版将具有蓝色背景,移动/触摸版将具有红色背景。

请查看以下示例:
https://jsfiddle.net/mcy60pvt/1/

要检查移动设备的长按选项,您可以使用此示例:
https://jsfiddle.net/mcy60pvt/3/

在上面的示例中,绿色方块在桌面和移动设备上都有:hover定义,但对于桌面版,背景将更改为黄色,而对于移动设备(通过长按),背景将更改为白色

以下是最后一个示例的CSS:

body {
    background: red;
}
div.do-hover {
  border: 1px solid black;
  width: 250px;
  height: 250px;
  background: green;
}
div.do-hover:hover {
  background: white;
}

@media (hover: hover) {
  body {
    background: blue;
  }
  div.do-hover:hover {
    background: yellow;
  }
}

在这个例子中 - 不支持:hover的浏览器将以绿色背景查看 hover me 盒子,当鼠标悬停(触摸/长按)时,背景将更改为白色。

更新

关于添加的伪代码:

.myelement {
    /* some styling #1 */
    /* note: no hover state here */
}
@media(hover: hover) {
    .myelement {
        /* some styling that override #1 styling in case this browser suppot the hover*/
    }
    .myelement:hover {
        /* what to do when hover */
    }
}

谢谢,但这让我陷入了同样的困境,即不支持悬停媒体查询的浏览器无法正确地工作。 - moogal
我会在答案中添加它,1分钟。 - Dekel
恐怕这是同样的问题 - Firefox 用户无法像其他浏览器一样使用 hover,因为它会返回 false。这就是为什么我试图反向操作(即“如果不是不支持”)。 - moogal
Firefox 桌面版/移动版/其他设备? - Dekel
3
好的,这是一个有些不同的问题。就像问“如何在只支持css3的浏览器中使用css4技巧?” :) 好吧,大多数情况下你做不到。如果Firefox忽略了hover:hover的定义- 你就没有什么可以用的东西(纯粹的css)。你可以使用JavaScript向body元素添加class,并基于该class使用CSS(is-firefox、is-support-hover、is-mobile等)。 - Dekel
显示剩余7条评论

11

感谢Dekel的评论,我通过在JS中运行逻辑并应用类来解决了这个问题:

例如:

const canHover = !(matchMedia('(hover: none)').matches);
if(canHover) {
  document.body.classList.add('can-hover');
}

然后在样式表中:

.myElement {
  background: blue;
}
.can-hover .myElement:hover {
  background: red;
}

我已在桌面版的Chrome、Safari和Firefox以及iOS版的Safari上进行了测试,结果符合预期。


就像所说的那样,JS几乎总能帮到你 :) 我对这个解决方案点赞。 - Dekel
非常聪明的回答。不错的东西。 - Drenai

7
你可以使用这个Sass混合器来为悬停状态添加样式,它会在触摸设备上使用推荐的替代方式:active。适用于所有现代浏览器和IE11。
/**
 Hover styling for all devices and browsers
 */
@mixin hover() {
    @media (hover: none) {
        -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
        &:active {
            @content;
        }
    }

    @media (hover: hover), all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
        &:hover {
            @content;
        }
    }
}

.element {
    @include hover {
         background: red;
    }
}

1
这是我找到的最佳解决方案,但顺便提一下,它不支持 Firefox 63 及以下版本。 - Pluto
@Pluto 感谢您的见解。那还不错,这些版本的全球使用率低于0.1%。 - Fabian von Ellerts

1
根据Artin的回答,我们可以使用@media not all and (hover: none)仅针对支持悬停效果的设备使用纯css。看起来很奇怪,但确实有效。
我将其制作成Sass混合器以便更容易使用:
@mixin hover-supported {
    @media not all and (hover: none) {
        &:hover {
            @content;
        }
    }
}

以下内容会在支持鼠标悬停的设备上,在悬停时将.container的背景颜色从红色更改为蓝色,对于触摸设备则不会有任何变化。
.container {
    background-color: red;

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

0

请不要使用媒体查询“hover”。我在我的27英寸显示器上使用鼠标工作,但是我的所有浏览器都设置为“hover:none”,尽管我喜欢并且能够经常悬停。也许我的所有浏览器都设置为hover:none,因为我的笔记本电脑连接了触摸屏外设。也许您可以尝试使用任何悬停媒体查询开发者mozilla.org/en-US/docs/Web/CSS/@media/any-hover

我制作了一个网站,您可以测试您的浏览器设置以解决此问题andreasburg.de/browser-hover-check.html


0
为了支持Firefox(请参见https://bugzilla.mozilla.org/show_bug.cgi?id=1035774),您可能需要编写一些规则两次。请注意,虽然问题中没有指定,但我已经添加了pointer: coarse,假设这些规则的目的是针对移动屏幕。
/* BEGIN devices that DON'T pinch/zoom */
/* If https://bugzilla.mozilla.org/show_bug.cgi?id=1035774 
is fixed then we can wrap this section in a ...
@media not all and (pointer: coarse) and (hover: none) {
.. and do away with the 'NEGATE' items below */

.myelement {
  /* some styling that you want to be desktop only (style as an anchor on desktop) */
  font-size: 14px;
  text-decoration: underline;
  border: none;
}
/* END devices that DON'T pinch/zoom */

/* BEGIN devices that DO pinch/zoom */   
@media (pointer: coarse) and (hover: none) {
  .myelement {
    /* style as a large button on mobile */
    font-size: inherit;  /* maintain e.g. larger mobile font size */
    text-decoration: none;  /* NEGATE */
    border: 1px solid grey;
  }

  .myelement:hover {
    /* hover-only styling */
  }
}
/* END devices that DO pinch/zoom */

随着移动屏幕变得越来越大,我们失去了像素尺寸和移动设备与桌面之间的关联(当您希望区分平板电脑和桌面电脑时已经是这种情况),因此组合使用(pointer: coarse)和(hover: none)将变得更加有用于针对移动设备。


2
这个漏洞已经在一年前修复了。 - Fabian von Ellerts

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接