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

Bla*_*bam 2 html javascript css jquery hover

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

如果触摸屏用户单击这些链接之一,浏览器会立即转到该href位置。这意味着悬停内容永远不可见!

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

$(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;
}
Run Code Online (Sandbox Code Playgroud)
.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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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

到目前为止我们所知道的

可以检测触摸设备: 使用 JavaScript 检测“触摸屏”设备的最佳方法是什么?

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

一般来说,有很多不同的可能的输入设备:https : //en.wikipedia.org/wiki/Input_device#Pointing_device

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

Bla*_*bam 6

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

悬停媒体功能用于查询用户hover 使用主指针设备在页面上的元素上的能力。如果设备有多个指针设备,则悬停媒体功能必须反映用户代理确定的“主要”指针设备的特性。(要查询任何可用指针设备的功能,请参阅任意悬停媒体功能。)

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

any-pointerany-hover媒体的功能是相同的指针和悬停媒体功能,但它们对应于提供给用户的所有指点设备的能力的结合。在任意指针的情况下,如果不同的指点设备具有不同的特性,则可以匹配多个值。

代码示例:

/* 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) { ... }
Run Code Online (Sandbox Code Playgroud)

官方草稿: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/samples/media-hover-pointer/

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

目前最好的解决方案很可能是将这些媒体查询与回退解决方案一起使用,使用触摸检测通过document.createEvent("TouchEvent");和鼠标检测通过mousemove.hasMouse