有一段时间前,我收到了 Dirk Tucholski 的一封电子邮件,他向我展示了一个名为 FLOWmarket 的网站。他想知道菜单系统是如何工作的。我觉得它看起来很整洁,所以开始着手用我的方式构建它。这个想法是,有一个很长的垂直链接菜单,并非所有链接都可见。当您上下滚动鼠标时,菜单会自动滚动以显示更多菜单项,并突出显示鼠标当前悬停的链接。
HTML
一个典型的菜单
<div id="menu">
<ul>
<li><a href="#">Nature</a></li>
<li><a href="#">Receivability</a></li>
<li><a href="#">Alone time</a></li>
<!-- etc -->
</ul>
</div>
初始 CSS
我们正在设置一个静态高度,因此让我们确保溢出值(目前)设置为 overflow: auto;
这样,无论 JavaScript 如何,菜单都将滚动且可访问。否则就是基本的样式。
#menu {
height: 360px;
overflow: auto;
}
#menu ul {
list-style: none;
}
#menu a {
text-decoration: none;
display: block;
color: black;
}
初始 JavaScript
这里的想法是等待菜单链接被悬停,然后相应地进行调整。我们将应用一个悬停类进行样式设置,然后上下移动一个内部 div(我们将附加它)以实现效果。但是到底向上或向下移动多少?为此,我们需要确切地知道我们正在悬停哪个链接。位置较高的链接(列表中更靠下)需要比位置较低的链接滚动列表更远。我们将获取此位置并应用速度乘数以获得要偏移的距离。要获取位置,我们将循环遍历它们并应用数据属性。
$("#menu").css("overflow", "hidden").wrapInner("<div id='mover' />");
var $el,
speed = 13.5, // needs to be manually tinkered with
items = $("#menu a");
items
.each(function(i) {
$(this).attr("data-pos", i);
})
.hover(function() {
$el = $(this);
$el.addClass("hover");
$("#mover").css("top", -($el.data("pos") * speed - 40));
// 40 is the top padding for the fadeout
}, function() {
$(this).removeClass("hover");
});
请注意,您可以访问 HTML5 数据属性(例如 <div data-pos=1>
),例如 $("div").data("pos");
,这简洁而酷炫。
淡出效果
如果您在 WebKit 浏览器中查看演示,您会看到菜单在滚动时从顶部和底部淡出。我只是通过使用在菜单顶部和底部绝对定位的 :before 和 :after 伪元素来实现这一点,这些伪元素具有白色到透明的渐变。
#menu:before {
content: " ";
position: absolute;
top: 0;
left: 0;
height: 50px;
width: 100%;
z-index: 2;
background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, rgba(255,255,255,100)),color-stop(1, rgba(255,255,255,0)));
}
#menu:after {
content: " ";
position: absolute;
bottom: 0;
left: 0;
height: 50px;
width: 100%;
z-index: 2;
background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, rgba(255,255,255,0)),color-stop(1, rgba(255,255,255,100))); }
根据需要使用 其他浏览器前缀。
这个“速度”问题
每个菜单项向上或向下移动的距离受速度乘数的影响。您可以在上面的 JavaScript 中看到它被设置为一个看起来相当随意的 13.5。我玩了一会儿,试图找到一种数学方法来根据菜单项数量、高度等计算完美的速度乘数,但没有得到任何好的结果。如果您能想到什么,请告诉我。当然,最好不必每次菜单更改时都调整该乘数。
键盘导航
以当前速度,这个菜单很难导航到您选定的精确菜单链接。为了帮助解决这个问题,我们可以添加一些键盘导航。这是通过监视 document
上的 keydown
事件并触发一个函数来完成的。为了减少代码重写,我们将跟踪当前活动的菜单项,根据向上箭头或向下箭头是否被按下调整它,然后相应地触发 mouseenter
或 mouseleave
事件,这些事件已设置为处理菜单功能。
$(document).keydown(function(event) {
cur = $(".hover").attr("data-pos");
// Down arrow
if (event.keyCode == 40) {
$("[data-pos=" + cur + "]").trigger("mouseleave");
if (cur != max) { cur++; }
$("[data-pos=" + cur + "]").trigger("mouseenter");
}
// Up arrow
if (event.keyCode == 38) {
$("[data-pos=" + cur + "]").trigger("mouseleave");
if (cur > 0) { cur--; }
$("[data-pos=" + cur + "]").trigger("mouseenter");
}
});
这里唯一未显示的部分是我们设置 cur
变量并在悬停函数中设置它的位置,但所有这些都在实时演示中。
关于可用性的胡言乱语!
这个想法的核心,即比用户预期更快地滚动菜单,不利于可用性。由于不熟悉且敏感的移动,难以选择您要查找的确切链接。我意识到了这一点。键盘导航在一定程度上有所帮助,但这可能也是一个不熟悉的想法。
这不是适用于世界上每个长菜单的解决方案(另请参见 此处)。这更像是一种有趣的效果。也许对于菜单不太重要的网站。也许作为显示诗歌的一种方式。它是一种很酷的使用体验,因此,如果这种体验确实适合该网站,那么可能可以接受一点可访问性方面的损失。我认为 FLOWmarket 网站(此效果的来源)很棒。
这看起来很酷,Chris。我同意你的观点,确实存在一些可用性问题,但总的来说,这是一种相当不错的技术。
感谢分享!
有趣!
假设您有一个字母顺序列表(在本例中显然没有,但是……),您能否通过添加类似 iPhone 上联系人列表的字母快捷方式来缓解一些可用性问题?
我不知道其他人怎么样,但该网站对我来说运行起来完全糟糕,几乎导致浏览器崩溃。不过,您的演示运行良好。
它看起来非常漂亮,但可用性很糟糕 :)
非常不错,但有点……快?
看起来像是此导航的精简版
http://www.queness.com/resources/html/scrollmenu/index.html
我将尝试将它们混合起来使其更流畅。
无论如何,谢谢:>
一如既往,很棒的效果。
抱歉我的问题很愚蠢,但仅使用 CSS3 过渡是否可以实现此效果?
谢谢 Chris!
我一时半会想不出办法。
感谢你的回复,Chris。
在我看来,如果不使用任何动态变量,例如鼠标位置等,这是不可能实现的(您可以尝试使用 IE 的“表达式”;-))
我离非 JS 方法最近的尝试只是放大悬停元素及其相邻同级元素
li {
font-size:1em;
-webkit-transition:all .2s
}
li:hover {
font-size:2em
}
li:hover + li {
font-size:1.5em
}
‘”–>window.location=’http://www.google.com’
这是一个有趣的函数……我算不上JS高手,但我很惊讶居然没有办法以这种方式减慢滚动速度。
今天我用FF 3.6.13查看你的网站,当我查看“键盘导航”时,得到了一些奇怪的结果。在使用上下箭头移动时,它似乎会选择列表中的2、3甚至4个项目。
我仍然对你在这里的帮助感到高兴和惊讶。新年快乐,继续努力!
我在键盘导航方面也遇到了同样的问题,如果#mover的高度可以根据边距、行高和速度自动调整就好了。
在我看来,这样效果要好得多,并且在禁用JavaScript时会降级为手动滚动条(对于那些担心可用性的人)。
http://valums.com/files/2009/vertical-menu/final.htm
我理解就CSS而言,这只是一个新奇的东西。但是,教人们在创建事物时保持最佳实践,这不是很重要吗?
好吧,无论如何,Chris,这篇文章很好,尽管存在可用性问题,但我获得了一些可以应用的好技巧。
谢谢。
我喜欢原始版本中的一个细节,在这里没有看到,那就是不仅可以在列表右侧悬停,还可以在左侧悬停并使其滚动。
WebKit的一个问题:假设已经滚动到列表的大约一半位置,鼠标离开列表区域,然后从上方重新进入——此时,由于覆盖层的“淡出”,我无法悬停或点击前几个项目。
非常棒,Chris新年快乐!
这太糟糕了。完全没用的垃圾。
你妈妈昨晚可不是这么说的。
我不确定菜单……也许减少一些项目并放慢速度。
但这是一个多么聪明的网站!!
感谢你的想法,并分享一些跳出“思维定式”的思考。
我不确定有多少人真的想参与讨论这个问题。但是,我要指出,基于想法的实现来否定一个想法的可用性是一个错误。想想把按钮做得太小,或者布局中有很多难以区分的区域:这两者都没有使按钮或布局的概念成为可用性问题,而是它们的实现成为了问题。正如其他人已经指出的那样,速度、可感知性等都可以进行调整,使其从可用性的角度来看成为一个非常可行的解决方案。
我恐怕不太认同这一点,一旦你的目光固定在你打算点击的选项上,你就会移动鼠标去点击它,它就开始移动,但是除非你移动缓慢,否则眼睛不容易跟随它的移动,当你尝试实际使用它时,需要一些时间来适应。
很棒的文章。抱歉挑剔,但“succicient”不是一个真正的单词。我想你是想说“succinct”。 :)
感谢修复。将隐藏此评论,因为它现在已不相关。
关于…移动的速度和精度。
你能在活动项目上方的<li>和下方的<li>添加更大的边距吗?这可以让尝试仅滚动一两个项目时的误差范围更大一些。
这个菜单很酷,但我同意它太快了。也许它还有其他用途,而不是菜单。我会考虑一下。
太敏感,太容易出错。它一次跳两三个项目,非常难以使用。但是,我对代码了解不多,我想,无法弄清楚原因或提供如何调整才能使其可用。
在本文引用的所有示例中,html元素的高度都为100%。在这种情况下,它工作得很好,但是当此滚动列表用于较长的文档时,会出现问题。列表不会滚动到末尾。我可以在WebKit中解决它,但它在FF中不起作用。
在theflowmarket网站上选择特定的菜单链接有点烦人。而且似乎很滑……不知道你怎么想。
一个词:不可用。
胡说八道!
是的,在指责别人之前先把整篇文章看完!
我觉得几乎每条评论都在抨击可用性,这很有趣。除了Chris已经指出的这一点之外,令人惊讶的是,很少有人认识到这可能是一个多么巧妙的设计元素。
基本思想——为用户关注的项目提供“突出”样式,同时不将其与内容中的位置分离——具有巨大的可用性潜力。它是Apple风格菜单的文本等价物(底部的那个),每个人似乎都喜欢它们。
不,它不是一个成品,它还没有准备好使用。(然而,它非常接近于原始的实现——任何抨击都应该指向FLOWmarket(他们可以处理它,他们有足够的“敢于失败”的准备)。但我认为它确实值得开发。我会关注它。我一直来这里寻找很酷的想法,而不是即插即用的东西(尽管我确实发现了两者——谢谢,Chris!)。
非常不友好。
这样的方法是否更好?
http://www.philosophydesign.com/examples/scroll.html
在这个例子中,我检查鼠标当前在导航中的位置,并根据该位置移动导航位置。我没有添加任何花哨的样式,但对我来说,这似乎更容易选择我想要的菜单项。此外,你可以在菜单中添加或减少菜单项,而无需更改JS中的任何变量。
你怎么认为?
非常棒的菜单,另一个问题是移动设备的可用性……我敢打赌,在手机上使用它会非常困难。
虽然我不是极简主义设计的忠实粉丝,但我喜欢这个菜单的想法。不确定它是否是SEO友好的,因为使用了脚本……我收藏了你的网站,很高兴从你这里学到一些技巧 :)
分享得很好。
分享得非常好。