检测客户端设备是否支持 :hover 和 :focus 状态客户端、状态、设备、hover

2023-09-07 23:00:49 作者:妳是◆我的永遠◇

听起来是一个简单的问题,但解决起来却非常具有挑战性.对于某些网站,我的内容只有在用户悬停/聚焦链接时才会显示.然而,链接本身有一个目标.

如果触摸屏用户点击其中一个链接,浏览器会立即转到 href 位置.这意味着悬停内容永远不可见!

三好课堂下载 三好课堂客户端 6.2.2.0 官方版 河东下载站

这就是为什么没有鼠标(或像魔术遥控器一样悬停的其他设备)的用户应该看到替代内容的原因.但是我该如何检测呢?

$(document).on('click','#my-menu-inner > ul > li > a',功能(e){如果(clientHasInputDeviceSupportingHover()){返回真;} 别的 {e.preventDefault();$('#for-no-hover-visitors').html('');$(this).clone().appendTo('#for-no-hover-visitors');$(this).next().clone().appendTo('#for-no-hover-visitors');}});功能客户端HasInputDeviceSupportingHover(){//我怎样才能检测到这个???if($('#checkhover:checked').length > 0) {返回真;}返回假;}

.clearfix::after {内容: "";明确:两者;显示:表格;}#my-menu-inner >ul {边距:10px;宽度:100%;背景颜色:黄色;列表样式类型:无;位置:相对;}#my-menu-inner >ul >李{向左飘浮;边距:20px;}#my-menu-inner >ul >李>一个 {填充:20px;边框:1px纯黑色;显示:块;}#my-menu-inner >ul >李>div.sub {位置:绝对;顶部:计算(100% - 20px);背景颜色:红色;填充:40px;显示:无;左:0;宽度:100vw;}#my-menu-inner >ul >li a:hover + div.sub, #my-menu-inner >ul >li a:focus + div.sub,#my-menu-inner >ul >李>div.sub:hover, #my-menu-inner >ul >李>div.sub:焦点{显示:块;}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></脚本>模拟客户端支持悬停:<input type="checkbox" id="checkhover"/><div id="我的菜单"><div id="my-menu-inner"><ul class="clearfix"><li><a href="http://www.example.com/foo/">foo</a><div 类="子"><ul><li><a href="http://www.example.com/mobile/">mobile</a></li><li><a href="http://www.example.com/users/">用户</a></li></ul></div></li><li><a href="http://www.example.com/bar/">bar</a><div 类="子"><ul><li><a href="http://www.example.com/never/">从不</a></li><li><a href="http://www.example.com/see-me/">见我</a></li></ul></div></li></ul></div></div><div id="for-no-hover-visitors"></div>

问题是clientHasInputDeviceSupportingHover().找出这一点最可靠的方法是什么?

到目前为止我们所知道的

可以检测到触摸设备:什么是最好的方法使用 JavaScript 检测触摸屏"设备?

鼠标检测至少可以onclick"工作:如何检测设备是否支持鼠标?

通常有很多不同的可能输入设备:https://en.wikipedia.org/wiki/Input_device#Pointing_device

非常欢迎通用/更可靠的解决方案.

解决方案

W3C 似乎已经意识到了这个问题并引入了悬停功能:

悬停媒体功能用于查询用户悬停的能力使用主要指针设备覆盖页面上的元素.如果一个设备有多个指针设备,悬停媒体功能必须反映主要"指点设备的特性,如由用户代理决定.(查询任何的能力可用的指点设备,请参阅任意悬停媒体功能.)

甚至还有一个媒体查询来检查是否有可能悬停:

any-pointerany-hover 媒体功能与指针和悬停媒体特征,但它们对应于并集用户可用的所有指点设备的功能.在里面任意指针的情况下,可以匹配多个值,如果不同的指点设备具有不同的特性.

代码示例:

/* 主要输入机制系统可以轻松将鼠标悬停在元素上 */@media(悬停:悬停){ ... }/* 主要输入机制不能悬停根本或不能方便地悬停(例如,许多移动设备模拟悬停当用户执行不方便的长按时),或者没有主要的指向输入机制 */@media(悬停:无){ ... }/* 一种或多种可用的输入机制可以轻松地将鼠标悬停在元素上 */@media(任意悬停:悬停){ ... }/* 一个或多个可用的输入机制不能悬停(或没有指向输入机制)*/@media(任意悬停:无){ ... }

官方草案:https://drafts.c​​sswg.org/mediaqueries/#hover

此功能仍然存在风险,但我真的希望它能够尽快得到全面支持,因为它已经被广泛支持:https://caniuse.com/#feat=css-media-interaction

进一步阅读:https://css-tricks.com/touch-devices-not-judged-size/

对于 Chrome,请在此处测试您的设备:https://googlechrome.github.io/样本/媒体悬停指针/

使用 JavaScript 进行测试:https://jsfiddle.net/Blackbam/zkd2cs0t/16/

目前最好的解决方案很可能是通过 document.createEvent("TouchEvent"); 使用触摸检测和通过 mousemove.hasMouse 进行鼠标检测的后备解决方案来使用这些媒体查询.

Sounds like a simple problem, but turns out to be quite challenging to solve. For some website I have contents that are only to be shown if a user hovers/focuses a link. The link however has a target itself.

If one of those links is clicked by a touch screen user the browser instantly goes to the href location. This means the hover contents are never visible!

This is why users which do not have a mouse (or another device to hover like a magic remote control) should see alternative content. But how can I detect this?

$(document).on('click','#my-menu-inner > ul > li > a',function(e) {

if(clientHasInputDeviceSupportingHover()) { 
  return true;
} else {
  e.preventDefault();
  $('#for-no-hover-visitors').html('');
  $(this).clone().appendTo('#for-no-hover-visitors');
  $(this).next().clone().appendTo('#for-no-hover-visitors');
}

});

function clientHasInputDeviceSupportingHover() {
    // HOW CAN I DETECT THIS???
    if($('#checkhover:checked').length > 0) {
      return true;
    }
    return false;
}

.clearfix::after {
    content: "";
    clear: both;
    display: table;
}

#my-menu-inner > ul {
  margin:10px;
  width:100%;
  background-color:yellow;
  list-style-type:none;
  position:relative;
}

#my-menu-inner > ul > li {
  float:left;
  margin:20px;
}

#my-menu-inner > ul > li > a {
  padding:20px;
  border:1px solid black;
  display:block;
}

#my-menu-inner > ul > li > div.sub {
   position:absolute;
   top:calc(100%  - 20px);
   background-color:red;
   padding:40px;
   display:none;
   left:0;
   width:100vw;
}

#my-menu-inner > ul > li a:hover + div.sub, #my-menu-inner > ul > li a:focus + div.sub,
#my-menu-inner > ul > li > div.sub:hover, #my-menu-inner > ul > li > div.sub:focus {
    display:block;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Simulate for Client supporting hover: <input type="checkbox" id="checkhover" />

<div id="my-menu">
  <div id="my-menu-inner">
    <ul class="clearfix">
      <li>
        <a href="http://www.example.com/foo/">foo</a>
        <div class="sub">
          <ul>
            <li><a href="http://www.example.com/mobile/">mobile</a></li>
            <li><a href="http://www.example.com/users/">users</a></li>
          </ul>
        </div>
      </li>
      <li>
        <a href="http://www.example.com/bar/">bar</a>
        <div class="sub">
          <ul>
            <li><a href="http://www.example.com/never/">never</a></li>
            <li><a href="http://www.example.com/see-me/">see me</a></li>
          </ul>
        </div>
      </li>
    </ul>
  </div>
</div>

<div id="for-no-hover-visitors"></div>

The problem is clientHasInputDeviceSupportingHover(). What is the most reliable way to find this out?

What we know so far

It is possible to detect a touch device: What's the best way to detect a 'touch screen' device using JavaScript?

Mouse detection at least might work"onclick": How to detect if a device has mouse support?

In general there are a lot of different possible input devices: https://en.wikipedia.org/wiki/Input_device#Pointing_device

A generic / more reliable solution would be very welcome.

解决方案

The W3C seems to have recognized this problem and has introduced the hover feature:

The hover media feature is used to query the user’s ability to hover over elements on the page with the primary pointing device. If a device has multiple pointing devices, the hover media feature must reflect the characteristics of the "primary" pointing device, as determined by the user agent. (To query the capabilities of any available pointing devices, see the any-hover media feature.)

There is even a media query to check if there is any possibility to hover:

The any-pointer and any-hover media features are identical to the pointer and hover media features, but they correspond to the union of capabilities of all the pointing devices available to the user. In the case of any-pointer, more than one of the values can match, if different pointing devices have different characteristics.

Code samples:

/* Primary input mechanism system can 
   hover over elements with ease */
@media (hover: hover) { ... }

/* Primary input mechanism cannot hover 
   at all or cannot conveniently hover 
   (e.g., many mobile devices emulate hovering
   when the user performs an inconvenient long tap), 
   or there is no primary pointing input mechanism */
@media (hover: none) { ... }

/* One or more available input mechanism(s) 
   can hover over elements with ease */
@media (any-hover: hover) { ... }


/* One or more available input mechanism(s) cannot 
   hover (or there are no pointing input mechanisms) */
@media (any-hover: none) { ... }

Official draft: https://drafts.csswg.org/mediaqueries/#hover

This feature is still at risk, but I really hope it will be fully supported soon as it is already widely supported: https://caniuse.com/#feat=css-media-interaction

Further read: https://css-tricks.com/touch-devices-not-judged-size/

For Chrome test your device here: https://googlechrome.github.io/samples/media-hover-pointer/

Test with JavaScript: https://jsfiddle.net/Blackbam/zkd2cs0t/16/

The best solution for now is most probably to use those media queries with a fallback solution using touch detection via document.createEvent("TouchEvent"); and mouse detection via mousemove.hasMouse.