支持悬停的设备的媒体查询

Media query for devices supporting hover

我想为支持悬停的浏览器(例如桌面浏览器)和不支持悬停的浏览器(例如触摸屏设备)提供不同的行为。具体来说,我想在支持它的浏览器上声明悬停状态,但不支持不支持它的浏览器,以避免移动浏览器通过额外的点击来模拟它,因为这会破坏页面上的其他交互 - 通过不定义悬停这些浏览器的状态是避免的。

我已经阅读了 Interaction Media Queries 功能,它看起来应该可以解决问题。我可以做类似的事情:

@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 */
  }
}

那么,有没有办法让这项工作按预期的方式进行,还是我走错了路?

来自规格:

none

Indicates that the primary pointing system can’t hover, or there is no pointing system. Examples include touchscreens and screens that use a drawing stylus.
Pointing systems that can hover, but for which doing so is inconvenient and not part of the normal way they are used, also match this value.

For example, a touchscreen where a long press is treated as hovering would match hover: none.

如果您的浏览器(mobile/touch)支持长按模拟悬停,hover: none的用法将不起作用。您可以做的只是使用默认值并覆盖它(默认 css 优先级):

body {
    background: red;
}

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

桌面将具有 blue 背景,mobile/touch 将具有 red 背景

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

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

在上面的示例中,绿色块对桌面和移动设备都有 :hover 定义,但是对于桌面设备,背景将更改为 yellow,对于移动设备(长按),背景将更改至 white.

这是最后一个例子的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 框,而 "hover" (touch/long-press) - 背景将变为白色。

更新

至于添加的伪代码:

.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 */
    }
}

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

例如

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 上对此进行了测试,它按预期工作。

not 应在媒体类型(屏幕、打印、所有等)而不是媒体功能(悬停、点等)前加上前缀。

错误:

@media not (hover: none)

正确:

@media not all and (hover: none)

是的,它不直观而且很奇怪。 Source (see comments).

所以你不需要javascript来替换媒体查询的结果。

根据 ,我们只能解决支持纯 css 和 @media not all and (hover: none) 悬停的设备。看起来很奇怪,但确实有效。

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

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

对于支持悬停的设备,以下内容会将 .container 的背景颜色从悬停时的红色更改为蓝色,对于触摸设备则没有变化:

.container {
    background-color: red;

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

要支持 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) and (hover: none) 的组合对于定位移动设备应该更有用,因为移动屏幕变得更大,我们失去了像素尺寸与移动设备与桌面设备之间的相关性(当您希望区分平板电脑时,情况已经如此)和桌面)

您可以使用此 Sass mixin 来设置悬停样式,它将使用推荐的替代品 :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;
    }
}