赞美明确的点击菜单

Avatar of Mark Root-Wiley
Mark Root-Wiley

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费积分!

我还记得,当我学会如何仅用 CSS 创建悬停触发式子菜单时,我的兴奋之情。(这可能是在阅读了A List Apart 上的这篇 2003 年文章之后。)当时,这确实是 CSS 的一个小技巧。说真的。真是狂野的时代。

事情是这样的

<ul class="my-menu">
  <li>
    <a href="page-a.html">Page A</a>
    <ul>
      <li><a href="page-b.html">Page B</a></li>
      <li><a href="page-c.html">Page C</a></li>
      <li><a href="page-d.html">Page D</a></li>
    </ul>
  </li>
  <!-- etc... -->
</ul>
/* Position submenus relative to parent list item */
.my-menu li {
  position: relative;
}

.my-menu ul {
  /* Hide my submenus by default */
  display: none;
  /* Position submenus, when open */
  position: absolute;
  left: 0;
  top: 100%;
}

/* Look, Ma! No onclick handler! */
.my-menu li:hover > ul {
  display: block;
}

如今,我们可以通过一个新技巧来提高仅用 CSS 创建的菜单的可访问性! 借助:focus-within,菜单可以在使用键盘进行导航时打开和关闭。

/* No IE11 support */
.my-menu li:focus-within > ul {
  display: block;
}

尝试使用鼠标和TAB键在演示中移动。

但时代不同了,我已经不是当年我第一次学习这些技巧的我了。从那时起,我已经构建了许多网站,并且在可用性、可访问性和内容策略方面学到了更多知识。现在,我发现悬停触发式菜单在这三个方面都存在缺陷。因此,几年前,我停止构建悬停触发式子菜单,转而使用点击触发式子菜单。(从这里开始,我将它们简称为“悬停菜单”和“点击菜单”。)

我认为你也应该停止构建悬停菜单。我将告诉你原因。

悬停菜单不一致

看看我构建的某个网站上的真实菜单

很简单,对吧?箭头图标显示除了“主页”之外,每个项目都有子菜单。但是,如果这些子菜单出现在悬停时,菜单至少有四种可能的工作方式,而且你可能已经体验过所有四种。

  1. 最上面的“父级”菜单项链接到一个页面,每个子菜单项链接到另一个页面。对于上面的例子,“服务”将是一个唯一的页面,子菜单中的每个链接也将是唯一的页面。

但在某处,第二种非常常见的模式出现了。

  1. 父级项具有href="#"— 甚至根本没有href😱,而唯一有效的链接在子菜单中。在我们的示例中,“服务”仍然是一个链接,但单击它不会发生任何事情。

这种不一致 — 父级项是链接还是不是链接? — 导致我在观看人们使用网站时感到非常困惑。有些人直接跳过有用的顶级页面,假设这些项目不是链接。而另一些人则认为顶级链接页面,并尝试单击它们。

这导致了你会遇到的第三种和第四种不太好的模式。我猜想,这些模式是为弥补前两种设置带来的混淆而演变的。

  1. 父级项和第一个子菜单项链接到同一个页面。更糟糕的是,父级项和第一个子菜单链接的链接文本不同,这违反了 WCAG 2.1 级 AA 可访问性标准
  2. 父级项链接到一个页面,其中包含无用的填充内容或仅包含子菜单中的链接。这个页面本身对任何访问它的人都没有实际用处。

最后两种配置会浪费那些知道父级项目是链接的人的时间,因为它们包含了冗余或无用的内容。

这是一个展示所有四种可能的悬停菜单设置的图表。

Image of a white menu with four menu items going from left to right. The menu is against a gradient background that goes from a burnt orange to a deep purple horizontally. Each menu item corresponds to one of the usability issues that were described.
当第一次看到悬停菜单时,访问者可能会合理地想知道这四种方式中的哪一种是菜单的工作方式。

访问者对悬停菜单感到困惑

无论我们如何实现悬停菜单,我们的访问者都可能会合理地想知道

  1. 我可以单击父级项目吗?
  2. 父级项目是否会链接到与第一个子菜单链接相同的页面?
  3. 即使父级项目是一个唯一的链接,它是否值得我花时间查看?

这让我们没有好的选择。它使我们无法满足雅各布的可使用性定律,即“用户希望您的网站与他们已经熟悉的其他所有网站一样工作”。在悬停菜单的实现方面没有标准,因此我们需要做一些不同的事情来提供一致的用户体验。

“分割按钮”菜单怎么样?

我见过的最不常见的菜单类型可能使用了“分割按钮”设计,其中父级项目是一个链接,一个单独的下拉菜单图标用于打开和关闭菜单。Twenty Fifteen 默认 WordPress 主题 使用了这种模式。因为它太不常见了,我发现访问者经常忽略顶级页面链接,研究表明用户不会认为标签和图标是独立可点击的

来自 Twenty Fifteen WordPress 主题的“分割按钮”菜单项
直到有人将鼠标悬停在箭头按钮上或将焦点放在箭头按钮上,他们可能不会猜到它与链接是独立的。

那么,更好的选择是什么?点击触发式子菜单!

点击菜单来拯救

与其依赖悬停交互或其他“创造性”(且令人困惑)的解决方案,不如构建这样的菜单,其中父级项目是按钮,点击它们可以显示和隐藏子菜单。这立即解决了悬停菜单问题,因为点击菜单的工作方式非常明确

  • 网站访问者必须单击父级项目才能查看其子菜单。
  • 所有链接都包含在子菜单中,除了没有子菜单的顶级项目(例如,“主页”。我们将在稍后处理这些顶级页面的情况。

仔细想想,点击菜单实际上是我们期望在大多数其他情况下出现的

  • 使用触摸设备?悬停并不是真的存在。
  • 使用应用程序菜单(例如,“文件”、“编辑”等)?这些菜单几乎不会在悬停时出现!
  • 使用鼠标以外的任何东西?按ENTER键或使用任何类型的开关控制激活链接更像是单击,而不是:focus相当于:hover

无论你的设备或输入方式是什么,“点击”都是一种更通用、更可靠的交互方式。让我们用它来让我们的网站菜单变得更加出色!

切换到点击菜单

我的直觉告诉我,很多网站最近都切换到了点击菜单。加入我们的行列吧!随着越来越多的网站做出这种改变,人们将再次形成对“网站如何工作”的简单且有用的期望(从而满足雅各布定律)。

当你第一次做出这种改变时,确实有些访问者可能会仍然期望悬停菜单。如果你问他们,他们甚至可能会说他们更喜欢悬停菜单。但是,我可以告诉你的是,我观察到人们使用点击菜单后,每个人都能很快明白并适应。

不要只相信我的话!美国网站设计系统 (USWDS) 的导航模式 使用了点击菜单。以下是他们的说法

避免使用悬停来展开下拉列表。悬停对于某些用户来说很困难,而且在触摸屏上无法使用。下拉列表应该在点击或使用键盘导航时展开。

Bootstrap 也使用点击菜单,出于同样的原因

归根结底,是用户意图。悬停状态的目的是指示某物可点击(带下划线的文本)… 点击的目的是实际执行某项操作,采取明确的行动。打开下拉菜单是一个明确的行动,并且应该只在点击时发生。

在同一篇文章中,有一个非常棒的见解

下拉链接中的插入符号相当于链接的下划线:它提供了一些关于点击此元素时将发生什么的提示。但不要将它误认为是提供足够的信息来在悬停时弹出下拉菜单。

所以我们并不是在探索未知领域。而且,英国政府设计系统 还提醒了我们:也许你根本不需要子菜单!他们的菜单只是一列链接,使用页面内的链接网格和手风琴来帮助访问者导航。说真的,在 CSS-Tricks 上也找不到子菜单!

点击菜单附带额外的好处!

你越使用点击菜单,你就会发现越多好处

  • 您决定是否需要类别/概述/着陆页……还是不需要! 而不是强迫内容与菜单结构匹配,并使用作为其他链接父级的链接,您的内容策略和信息架构决定了您需要哪种类型的页面以及如何标记它们。如果服务概述对您的访客有帮助,请将“服务概述”或“所有服务”作为“服务”子菜单中的第一个项目。
  • 子菜单保持打开状态,直到关闭。 悬停菜单有一种讨厌的方式,当人们碰到鼠标光标甚至只是 尝试点击子菜单链接 时就会消失。对于“飞出”而不是位于父项目下方的子菜单来说,尤其如此。点击菜单的持久性创造了更加“稳固”的体验,因此用户信任界面并且不会感到沮丧。
  • 对于超级菜单,持久子菜单行为更为重要。 当访客需要更多时间来查看子菜单内容时,他们无法承受菜单意外关闭。
  • “移动”和“桌面”菜单的 JavaScript 相同。 无论菜单隐藏在汉堡包后面还是在移动设备上可见,交互始终相同。我只需要更改我的 CSS 才能创建响应式点击菜单。

构建点击菜单

当我着手构建自己的可访问点击菜单脚本时,我发现没有一个关于如何做到这一点的标准。我自己的想法和代码受到以下方面的很大影响

我对实施研究的主要收获

  • 您单击以显示子菜单的元素应该是 <button>,因为它不会链接到页面。
  • 使用 aria-expanded(在 <button> 上!)来传达子菜单的打开和关闭状态。
  • 使用 display: nonevisibility: hidden,以便键盘用户在子菜单关闭时无法访问它们。
  • aria-controls 是垃圾,但您不妨添加它。
  • 不要 使用 role="menu"(以及整个 ARIA 菜单模式)或 aria-haspopup。这些感觉相关,但它们不适用于构建导航菜单。
  • 关闭打开的子菜单时
    • 另一个子菜单打开
    • 用户单击菜单外部
    • 当焦点在打开的子菜单内时,用户按下 ESC 键。(并非所有用户都期望这样做,但我认为这是一个不错的补充。)

由于点击菜单需要 JavaScript,因此我们应该考虑如何在 JavaScript 出于任何原因失败的情况下 逐步增强 此菜单。毕竟,我们的经典悬停 CSS 技巧还是有用的!

我开始将我的点击菜单构建为一个仅使用 CSS 的悬停菜单,该菜单使用 li:hover > ulli:focus-within > ul 来显示子菜单。然后,我使用 JavaScript 创建 <button> 元素,设置 aria 属性,并添加事件处理程序。这意味着菜单在没有 JavaScript 的情况下仍然可以正常工作,并且与我在首选 CMS WordPress 中构建的仅链接菜单配合得很好。

您可以查看 我使用的脚本,但我首先承认可能还有更好的脚本。重要的是您用真实用户测试它……并停止使用悬停菜单。😃