手机端浏览器里的下拉菜单实现

在浏览器里, 试图实现一个下拉菜单。

利用hover弹出

<nav>
  <a class="menu-bars" href="#">Menu</a>
  <ul class="menu">
    <li><a href="https://google.com/">Google</a></li>
    <li><a href="https://bing.com/">Bing</a></li>
  </ul>
</nav>

<style>
ul.menu {
  display:none;
}
nav:hover ul.menu {
  display: block;
}
</style>

这在桌面端浏览器上工作没问题。

  • 鼠标放在"Menu"链接上时,触发:hover属性。
  • :hover属性会向上传递给父元素。这点很重要。
  • nav:hover ul.menu触发菜单显示。
  • 菜单作为<nav>的子元素,确保了nav:hover继续有效。
  • 直到鼠标离开菜单区域,导致nav:hover失效,进而隐藏菜单。

但在iOS上(Safari or WebView):

  • 触摸屏没有hover这个动作
  • 点击(Tap)"Menu"时,菜单可以正常弹出
  • 但却无法实现菜单隐藏

Double-Tap Link Issue on iOS

这里有两个很有意思的观察结论

  • 点击(Tap)产生了一个hover动作
  • 这个hover动作无法自动移除

参见 The Annoying Mobile Double-Tap Link Issue

""" This is where the people at Apple might have been a bit too smart. They realized that there was a lot of functionality on the web relying on hover states and so they figured out a way to deal with that in Safari for iOS. When you touch an item on a webpage, it first triggers a hover state and then triggers the “click”. The end result is that you end up seeing styles applied using :hover for a second before the click interaction happens. It’s a little startling, but it does work. So Safari on iOS very much cares about your styles that have :hover in the selector. They aren’t simply ignored. """

利用checkbox弹出和隐藏

有人想到一个很聪明的方案。

<nav>
  <label for="menu-bars">Menu</label>
  <input id="menu-bars" type="checkbox">
  <ul class="menu">
    <li><a href="https://google.com/">Google</a></li>
    <li><a href="https://bing.com/">Bing</a></li>
  </ul>
</nav>

<style>
ul.menu {
  display:none;
}

input#menu-bars {
  display:none;
}

input#menu-bars:checked + ul.menu {
  display: block;
}
</style>
  • 不再利用父元素实现对菜单的控制
  • 利用兄弟节点(Sibling)实现对菜单的控制
    • CSS选择器 A + B表示紧跟在A后面的B
    • // 选择器 A ~ B表示跟在A后面的B(不必紧跟)
  • 利用checkbox的:checked属性保存菜单状态
  • 利用label的for属性响应用户的点击(Tap)