这是一个相当古老的用户体验概念,我已经有一段时间没听到有人讨论了,但在多级下拉菜单的情况下仍然适用。像鼠标这样的细粒度指针有时必须穿过非常狭窄的通道才能准确地到达下拉菜单中所需的位置。很容易出错(使鼠标指针离开路径)并因其关闭而受到惩罚。也许我们可以减少这种挫败感。
基本的 CSS 方法
下拉菜单通常设计为通过父元素的 :hover
状态在 CSS 中显示子菜单。或者在 JavaScript 中使用 mouseenter
/ mouseover
事件并更改状态。所以诀窍是尝试阻止任何这些事件太容易发生。扩大走廊,就像那样。
我开始思考这个问题的全部原因是因为 CodePen 中主下拉菜单的子菜单走廊非常狭窄。为了在瓶颈处扩大它们,我在子菜单中添加了几个伪元素。如果鼠标移到这些元素上,不会发生任何事情,就像鼠标在子菜单中一样正常。

这是一种超轻量级的技术,只需要 CSS,我喜欢。唯一的轻微危险是您可能会覆盖大量相邻的菜单项,这意味着用户可能将鼠标悬停在合法的菜单项上而无法单击它。我想在很多情况下,他们只需稍微移动一下鼠标就可以了,但这绝对是在太小和太大之间进行权衡。
这可以追溯到 2005 年和一个经典的 Position is Everything 演示

以及可能的一个 Thierry Koblentz 演示。
扩大 CSS 边界
John Gardner 创建了一种方法,所有菜单周围都有额外的空间,这些空间提供了宽容的悬停偏移。

看起来这个从互联网上删除了,抱歉!有很多 CodePen 上的 CSS 下拉菜单 可以探索。
(取消)悬停意图
您听说过“悬停意图”吗?这是一个概念,您不会立即对鼠标位置事件做出响应。您等待一小段时间,这样您就可以确定用户想要一个反应。这就像故意的延迟。它用于 UI 在没有它的情况下可能过于灵敏的情况。
我们可以称之为取消悬停意图的反面。就像我们立即对悬停事件做出反应,但在一段时间内不对悬停离开做出反应。在 CSS 中,您可以执行以下操作
.submenu {
visibility: hidden;
transition: 0.2s 1s; /* delay of 1 seconds on hover off */
}
.parent:hover .submenu {
visibility: visible;
transition-delay: 0s; /* react immediately on hover */
}
请注意,我们在这里使用 visibility 属性,它是可过渡的,而不是 display 属性,它不可过渡(奇怪的是)。
JavaScript 也当然能够实现取消悬停意图。您会像防抖一样处理它,除非经过一段时间,否则您不会调用执行关闭的函数。这可以通过一个 setTimeout 函数来实现,如果鼠标返回,则清除该函数。这过于简单化了,但是
var timer;
$(".parent").on("mouseover", function() {
clearTimeout(timer);
openSubmenu();
}).on("mouseleave", function() {
timer = setTimeout(
closeSubmenu
, 1000);
});
function openSubmenu() {
$(".submenu").addClass("open");
}
function closeSubmenu() {
$(".submenu").removeClass("open");
}
这些取消悬停演示都没有通过扩展大小来解决走廊问题,而是通过宽容鼠标位置的快速偏差来解决。
避免狭窄的通道
没有规定子菜单下拉菜单需要向侧面展开。如果它们直接在下方打开,则通道保持宽阔。以下是 Timothy M. LeBlanc 的一个示例
使用 JavaScript 生成的三角形来美化
几年前,Ben Kames 发表了一篇关于此主题的精彩文章。他正在查看 Amazon.com 下拉菜单的响应速度,与使用延迟策略来处理可用性的其他下拉菜单相比。神奇之处在于数学!如果鼠标以合理的角度移动到新打开的子菜单,它就不会触发其他菜单项。视觉辅助

Ben 将其变成了一个 jQuery 插件,您可以 进行演示。
他对这一点也非常正确
我相信这个问题在很多年前就被解决了,被遗忘,重新发现,再次解决,被遗忘,重新发现,再次解决。
这是我们行业中许多事情的悲哀真相。
Jon Neal 尝试删除 jQuery 依赖项并使用“重心坐标”改进数学。
Alex Popov 写信说他尝试了这个演示并改进了其功能。我没有时间重新加载所有内容到我的大脑中以弄清楚功能差异,但是如果您深入研究所有这些内容并正在查看可能性,这里有一个指向 Alex 版本的链接。
其他问题
我认为一位智者曾经说过
“有时访问您网站的访客会有鼠标,有时则没有。”
因此,希望您的下拉菜单也能与触摸屏配合使用。您当然可以使它们正常工作!您还可以决定是否要将所有代码捆绑在一起以提高效率,或者是否需要某种功能检测来根据需要加载不同的脚本和样式(或两者的组合)。
键盘可访问性是下拉菜单的另一个经典问题。我只是不想让您认为帮助鼠标移动是您为获得良好的下拉菜单 UX 所需做的全部工作。总有改进的空间!
非常棒的例子
有趣的东西!解决这个问题的方法有很多。
内容越多,问题越多,尽管我不得不争辩说,拥有一个庞大的子菜单树本身可能就是糟糕的用户体验。
从未想过为此使用伪元素,好主意!
将您现有的窄走廊技巧(红色矩形)与(未)悬停意图技术结合起来,似乎可以实现一个非常流畅的修复方案。使用更大、更宽容的伪元素(或子菜单上的重叠边距),例如使用 0.1 秒的过渡。这样,您可以在通往子菜单的路上裁剪角,但如果您确实需要下一个元素,则延迟很小。
您可以尝试使用 CSS 三角形(例如边框技巧)将您的不可见正方形辅助元素转换为三角形吗?它可能会稍微减少对其他菜单项的干扰。您甚至可以使三角形在水平方向上更长,同时最大限度地减少干扰。
使用CSS 三角形的问题在于,它们并不是真正的三角形,而是两个或三个边框透明的正方形,因此它们看起来像三角形。
不过,可以使用小的 SVG 片段(在 DOM 中更重)。或者可能更好,CSS
clip-path: polygon()
来获得三角形区域。您可以旋转一个元素……这将保持鼠标看起来位于某个元素之上与实际位于该元素之上的关联性。使用一些 JS 魔法来确定需要多大的矩形和旋转角度,以便一个点是鼠标激活下拉菜单的位置,而两个相邻点位于下拉菜单的最近顶部和底部角(对于水平打开的菜单)或左侧和右侧角(对于垂直打开的菜单)(插图)。
我长期以来一直使用过渡延迟技术,我认为它效果很好。
完全正确!在我看来,这是最好的方法。
感谢您提到这一点。我也一直在为此使用过渡延迟。这是一个在超级菜单上实现过渡延迟的示例。请注意,当菜单打开时,您可以采用对角线鼠标路径到达子链接。http://sparkexperience.com/projects/mclaren/member/?for=individualgroup
我同意 Matt 的观点。在我看来,过渡延迟是避免导航问题的最优雅方式。
不错的文章。很高兴我不是唯一一个遇到下拉菜单可用性问题的人。这里有一些不错的解决方案。
好文章,我过去同时使用过伪元素和延迟技术。
我觉得触摸事件没有那么简单。
我们可以只使用点击事件触发下拉菜单,但如果用户真的想转到该整个类别的登录页面怎么办?
我倾向于始终使用一个登录页面,其中包含到子页面的导航,以便触摸设备仍然可以导航到所需的位置。
对于低于导航断点的屏幕,“移动”菜单允许您根据单击菜单项的哪一部分来触发子菜单或导航到登录页面。我不希望在较大的屏幕上失去桌面上的鼠标交互,因此这个问题在较大屏幕上不会出现。
简单。第一次点击展开下拉菜单并添加一个名为“clicked”的类。
如果元素具有“clicked”类,则第二次点击将导致 linktarget。
gergfegrege:这可能有效,但我认为这会导致非常糟糕的用户体验,因为网页用户已经被引导不要双击网页。很少有用户知道可以导航到父页面,除非您提供某种视觉提示。
我同意您关于双击的观点。
我在一些具有多级导航的网站上处理过这个问题。当显示移动菜单并且存在子导航时,我会复制父导航项并将其插入为子链接。当您单击菜单项时,将显示子导航,并且子菜单的第一个子项是到该登录(或父)页面的链接。如果一开始没有子项,我不会这样做,而是将其链接到页面。如果您这样做,则需要一个图标或某种方式来显示存在子菜单。
此codepen 使用此方法。这也使用后退导航项在不同的导航级别之间导航。
这很棒。我一直在使用 superfish 进行导航,这些技巧都可以与它一起使用。感谢分享。
作为一些背景信息,我记得 Bruce Tognazzini 将此描述为苹果公司已故的人机界面小组在 80 年代解决的问题。解决方案与亚马逊下拉菜单中实施的解决方案非常相似。
哇!非常棒的文章!谢谢您
我确实喜欢 Chris 制作 codepen 下拉菜单的方式。简单有效。我唯一的问题,这是一个很小很私人的问题:当您将鼠标悬停在伪元素上时,链接项上的悬停样式会消失,因此您看不到当前项仍然处于活动状态。
我认为实现此目标的唯一方法是将
:hover
状态更改为应用于.has-submenu
,或在.has-submenu
上复制:hover
,例如http://jsfiddle.net/ahallicks/cLofnrcd/
根据您的想法,我创建了以下脚本以允许嵌套引导导航菜单。它们完全响应,不需要走廊或其他东西。
https://github.com/dsentker/BootstrapSubnav
看看 voronoi。用户界面算法 -> https://www.youtube.com/watch?v=90NsjKvz9Ns
我总是设置一个计时器。它是最短、最快捷、最简单的解决方案。我知道它需要 **JavaScript**,但老实说,您现在如何 *在没有 JavaScript 的情况下浏览网页*。此外,使用计时器,我可以自定义时刻之间的关系。进入与退出、下拉级别和按钮到按钮可以根据时间而有所不同。我使用计时器做的另一件事是在移动设备上进行菜单反应。
一次一个选择器地使网页防呆。干得好,Chris,我过去也寻找过这个问题的解决方案,而您终于想出了一个真正有效的并且效果很好的解决方案。
好主意
说真的,什么是 Libero?
太奇怪了,我昨天正在处理一个三级并排菜单,并且遇到了完全相同的问题。谢谢!
关于键盘访问,我们为Nichols College设置了一个非常不错的键盘跟踪器。代码也在Github上。
不错!以前从未想过将伪元素和延迟整合到整个菜单图片中!谢谢!
这是我在 2014 年对这个问题的看法
http://playground.idesigned.cz/projects/hoverintentmegamenu/
我也使用了伪元素。但通过旋转和动画来覆盖更多空间。这个解决方案介于你的“基本 CSS 方法”和“亚马逊的复杂 JavaScript 三角形”之间。
我无法告诉你这个解决方案是否对用户有效,因为我开发此代码片段的项目尚未投入生产。
你只需要在你的触发器中添加一个超时,然后清除超时。
我必须同意 Tim Rourke 的观点,嵌套菜单通常意味着某些事情出现了严重错误……在一个大型美国眼镜零售商的电子商务网站上工作,我诚实地认为,如果你从顶级菜单链接中创建子菜单,那么你的文案需要改进;或者你的网站过于复杂,阻碍了营销效果。
自动完成、过滤器、标签、漂亮的侧边栏或侧向滚动面包屑式菜单(类似于旧的 Flash 菜单),总是比下拉菜单效果更好,并且通常没有大型菜单树可能存在的性能和缓存问题;因此,你可以修复菜单,同时提高网站速度!