基于Web标准的UI组件 — 菜单

菜单(Menu)是最基本最常见的网页UI元素之一,它的主要功能包括:
  1. 引导用户发现网站的内容;
  2. 协助用户执行某一特定的操作。

  一个完整的菜单是一组菜单项(Menu Item)的集合,所有的菜单项在逻辑上应该是并列、平级的关系,它们指向相互之间没有隶属关系的内容或功能。

  菜单项可以是链接,也可以是另一组菜单项的集合,即二级菜单(Sub-Menu)。

菜单项的文案设计
  1. 明了:把意思表达清楚是一个菜单项文案的最基本要求。
    根据菜单的两种基本功能,“指向内容”的菜单项最好是一个概括内容的名词或名词性短语(如“诗歌”、“古典小说”),“执行操作”的菜单项最好是一个动词或动宾短语(如“订阅”、“订阅新闻”)。
  2. 直白:所有的网站是给用户看的,就按用户们习惯的大白话来和他们交流吧。
    举个例子:某门户网站提供了针对宽带用户的在线视频服务,指向这一服务的菜单项上写着“宽频”。中国的大多数互联网使用者都是比较初级而且不懂技术的,所以用“视频”或“在线视频”对他们来说会更加明白清楚(要不是“小电影”有某些其他意思,不然这个词可能更合适一些)。
  3. 简短:如果对“简短”原则需要更多解释的话,那就是不要为了“简短”而忽视了“明了”与“直白”。
基本的XHTML结构

  在XHTML的一大堆标签中,有一个被99.99%的Designer和99.98%的Developer忽视的标签:menu。它的用法与ul一样,内部可以包含一系列的li元素来构成菜单项,所以用它来构建菜单是再合适不过的了。如下:

<menu>
	<li><a href="/movie/">电影</a></li>
	<li><a href="/music/">音乐</a></li>
	<li><a href="/software/">软件</a></li>
</menu>

  查看效果(例1)

  这里需要特别说明一下,menu标签在XHTML Strict中已经不存在了,如果基于“向前兼容”的考虑,建议使用ul来代替menu。如果你的DocType是XHTML Transitional,那么使用menu是完全没问题的(包括通过校验)。具体怎么使用请根据你的实际情况选择,在这篇文章中我将使用menu标签。

菜单项提示

  设计菜单项文案时,“简短”与“明了”是一对矛盾,在无法用几个字说得很明白的情况下,就需要“菜单项提示(Menu Item Tooltip)”了。当鼠标悬停在某个菜单项上的时候,会弹出相应的提示,对此菜单项的内容和功能作出更进一步的说明。

  XHTML中的title属性就是用来提供这项改善可用性的功能:

<a href="/movie/" title="最新院线电影下载">电影</a>

  查看效果(例2)

最简单的菜单

  到目前为止我们写好了菜单的XHTML代码并考虑了可访问性和易用性方面的问题,但这当然还称不上一个可以拿得出手的菜单。不过也有人把这样的菜单拿出来用的,比如apache.org这个bt的技术组织@_@,下面咱就帮他们改个稍微好看点的菜单。

  先把menu的缩进效果和li前面的点去掉,并定义一个合适的宽度:

menu{
	margin:0;
	padding:0;
	list-style:none;
width:120px; }

  查看效果(例3)

  再为菜单项设置盒模型风格,注意IE和Firefox/Opera之间在盒模型上的差异:

menu li{
	/*高度20px*/
	height:20px;
	/*定义每个菜单项之间的间隔,并用!important*/
	/*解决IE与Gecko浏览器之间的盒模型差异*/
	margin-bottom:4px !important;	
	margin-bottom:2px;
}

  接下来是最关键的一步,请仔细看注释。

menu a{
	/*定义a为块级元素,方便用盒模型属性定义外观*/
	display:block;
	/*定义尺寸*/
	width:100%;
	height:20px;
	/*盒模型风格*/
	background-color:F6F6F6;
	border:1px solid #DDD;
	/*文字样式*/
	font:11px arial;
	text-decoration:none;
	/*文字垂直居中*/
	line-height:20px;
	/*文字水平居中*/
	text-align:center;
}

  查看效果(例4)

  接下来很轻松了,简单设置一下链接在四种状态下的样式,使菜单能够与鼠标覆盖事件交互:


menu a:link,menu a:visited{
	color:#333;
}
menu a:hover,menu a:active{
	color:#F50;
}

  查看效果(例5)

  也可以把鼠标效果做得更明显一些,比如变化一下背景色:


menu a:hover,menu a:active{
	background-color:#FFEFE6;
	border:1px solid #F60;
}

  查看效果(例6)

横向的菜单

  制作横向菜单的方法大致有两种:浮动与绝对定位。

  浮动法的思想很简单:让每一个菜单项都向左浮动,最终排成一横排。我们只需对上面的CSS做一些小小的改动就可以了:

menu{
	/*去掉menu的宽度,如果你的页面有宽度限制,那么也可以设在这里*/
	margin:0;
	padding:0;
	list-style:none;
}
menu li{
	/*指定li的长与宽*/
	height:20px;
	width:120px;
	/*让它向左浮动*/
	float:left;
	/*设置菜单项之间的间隔*/
	margin-right:4px !important;
	margin-right:2px;
	/*解决IE与Gecko浏览器之间的盒模型差异*/
	margin-bottom:4px !important;	
	margin-bottom:2px;
}

  查看效果(例7)

  这种方法不仅可以方便地创建横向菜单,它的思想同样用于在“流动布局”中罗列一些相似的内容,是一种应用很广泛的布局方法。

  再讲“绝对定位”的方法。很多人(包括一些Web标准实践经验非常丰富的人)对绝对定位有一种莫名其妙的反感,I don't know why。事实上它是一种极其重要的CSS布局方法,只要在使用时掌握那么一点点小窍门,你不会碰到让人沮丧的布局错乱或者其他什么古怪的结果。当然我也不是说绝对定位是万能的,“合适的才是最好的”,何时使用取决于具体的情况。

  回到菜单的制作上,如果你的菜单项长短不一,或者高低起伏,总之是不那么规则的时候,就可以使用绝对定位来实现。首先需要对上面的XHTML作一些小改动:给每个菜单项一个id

<menu>
  <li id="miMovie"><a href="/movie/" title="DVDRip">电影</a></li>
  <li id="miMusic"><a href="/music/" title="mp3">音乐</a></li>
  <li id="miSoftware"><a href="/dl/" title="共享">软件</a></li>
</menu>

  三个菜单项的id有一个共同的前缀——mi(即Menu Item的缩写),用于和其他元素的ID命名区分。这种命名方式纯粹是我的个人喜好,来自于以前用delphi和VB开发软件时的习惯。另外一些缩写包括mnu(Menu,菜单)、btn(Button,按钮)、pnl(Panel,面板)、lst(List,列表)、tab(Tab Menu,选项卡)等等。这样做的好处是可以有效防止id命名重复,同时在CSS中也可以只看命名就知道元素的UI类型。

  接下来就是CSS的工作了。先给menu定好长宽、去除缩进等等:

menu{
	width:360px;
	height:20px;
	margin:0;
	padding:0;
}

   接下来的一步很重要,给menu指定为相对定位:

menu{
	position:relatvie;
	width:360px;
	height:20px;
	margin:0;
	padding:0;
}

  如果跳过了这一步,后面你会发现菜单项的“绝对定位”并不是以menu为参照物,而是以浏览器窗口的左上角为坐标原点,当然这不是我们想要的效果。

  再设置菜单项共同的属性和相同的纵坐标:

menu li{
	position:absolute;
	top:0;
	list-style-type:none;
	width:120px;
	height:20px;
	line-height:20px;
	text-align:center;
}

  最后用id选择单个的菜单项指定其“个性”的横坐标属性:

#miMovie{
	left:0;
}
#miMusic{
	left:120px;
}
#miSoftware{
	left:240px;
}

  查看效果(例8)

  绝对定位对a标签的定义与浮动法基本一致,请查看例8的源代码。

  以上讲到的技术与技巧足以应付一般的菜单制作了,apache.org也应该会对我们修改后的菜单感到满意^_^。在下一篇文章中我会更详细地介绍基于Web标准制作菜单的高级应用和技巧。

指示当前活动菜单项

  当用户点击某菜单项进入网站相应的栏目,我们通常会希望这个菜单项表现出与其它菜单项不同的视觉特征,使用户明确地了解自己所处的“地点”而不至于在站点中迷路。我一直想不好应该是给这个菜单项一个什么样的名字,暂且称为“当前活动菜单项(Currently Active Menu Item)”吧,如果你有什么好想法请一定在右边留言告诉我,谢谢^_^。

  当前活动菜单项对创建良好的用户体验具有非常重要的作用,一个负责任的UI设计师是绝对不会忽视它的。实现的方法至少有两种:“直接指示”与“自上而下的指示”。

  “直接指示”的方法即直接给当前活动菜单项相对应的li元素一个适当的class属性,再在CSS中为这个class重载一般菜单项的视觉属性,使它表现出“独特”的视觉特征。说得挺悬忽,做起来很简单,我们还是用apache.org的菜单为例,并假设已经点击“DB”项进入了相应的栏目:

<li class="active">
  <a href="//db.apache.org/" title="Database access">DB</a>
</li>

  XHTML只要做这么一点小小的改进就可以了,CSS的改动也不大,只要增加这么一段:

menu li.active a{
	background-color:#E8F3FF;
	border:1px solid #05F;
}

  查看效果(例9)

  “自上而下的指示”并不直接在某个菜单项上指明它特殊的身份,而是先给每个菜单项命名,再在菜单项的“上级(比如body元素)”处指明哪个菜单项被选中了(颇有些类似皇帝翻牌选择当晚“临幸”的妃子^_^)。

  我们拿上篇文章中使用”绝对定位”的那个菜单为例,假设“软件”项被选中:

<body class="chlSoftware">
<menu>
  <li id="miMovie"><a href="/movie/" title="DVDRip">电影</a></li>
  <li id="miMusic"><a href="/music/" title="mp3">音乐</a></li>
  <li id="miSoftware"><a href="/dl/" title="共享">软件</a></li>
</menu>
</body>

  body元素的class设置了当前页面所处的频道(栏目),也就是此处chl前缀的意思——Channel。根据这个class就可以设置“临幸”的规矩了……-_-|||

body.chlMovie li#miMovie a,
body.chlMusic li#Music a,
body.chlSoftware li#miSoftware a{
	background-color:#E8F3FF;
	border:1px solid #05F;
}

  查看效果(例10)

  可能的情况下我建议使用第二种方式,理由如下:

  1. 写后台程序的时候比较方便,只需判断当前所处的栏目给body设置class即可(怎么判断?那可不是我的事儿....);
  2. 扩展性好,不仅可用于指示当前活动菜单项,也可以给页面上的其他元素提供当前状态的信息。比如你想让每个栏目有不一样的主色调,知道怎么办了吧^_^;
  3. 当皇帝比较爽……
带图标的菜单项

  做到现在我们的菜单还都是光秃秃的,某些朋友可能已经对Web标准技术在视觉效果上能走多远产生怀疑。下面我们就把图片引入到菜单的制作中,先从最简单的讲起——给菜单项加个图标“”。我们以例9的菜单为基础,对a元素的样式做些小修改:

menu a{
	/*定义a为块级元素,方便用盒模型属性定义外观*/
	display:block;
	/*定义尺寸*/
	width:100%;
	height:20px;
	/*盒模型风格*/
	background-color:#F6F6F6;
	border:1px solid #DDD;
	/*文字样式*/
	font:11px arial;
	text-decoration:none;
	/*垂直居中*/
	line-height:20px;
	/*水平居中*/
	text-align:center;
	/*文字缩进*/
	text-indent:20px;
	/*图标*/
	background:#F6F6F6 url(i/arrow.gif) 5% 50% no-repeat;
}

  查看效果(例11)

  这里有三点需要说明一下:

  1. 去除文字水平居中后菜单项的文字都紧贴左侧排列,我们需要给图标留出一定的空间。常用的方法(也是最容易想到的方法),就是使用padding-left。但这样会面临IE的盒模型Bug,虽然解决起来也很方便,但总不如用text-indent来得自然,更何况这样没有任何的Bug需要处理。
  2. 为什么不把图标直接用img标签插入到XHTML文档中?因为这些图标仅仅是装饰作用,它们并不是这个网页真正的“内容”,所以它们出现在XHTML代码中是不合适的。另外用背景图的方式处理也更方便更节约网络流量。反过来说,如果这个图标是一个logo,比如Apache HTTP Server那支著名的羽毛,建议你把它加入到XHTML代码中(别忘了alt属性),因为它是这个网页真正想要表达的“内容”。
  3. 关于如何正确设置背景图,我这里就不多说了,请参考小雨的《CSS2.0中文手册》中background部分。需要注意的是Opera对背景图定位有一些怪脾气,请参考我的另一篇文章
背景图翻转技术

  这又是一个很实用的技术。当我们对简单的盒模型风格不满意的时候,自然会想到使用背景图来创建更有个性的菜单项,实现的方法也很简单,我们还是在例9的基础上做修改。

  先看看两张背景图的效果:

  普通状态(bk01.gif):
   鼠标覆盖(bk02.gif):

  CSS的改动也不大,我就拣重要的讲(开始偷懒了……^_^):

menu a:link,menu a:visited{
	background:transparent url(i/bk01.gif) 0 0 no-repeat;
}
menu a:hover,menu a:active{
	background:transparent url(i/bk02.gif) 0 0 no-repeat;
}

  查看效果(例12)

  Yes,就这么简单,只要给a元素的四种状态设置相应的背景图就可以了。这种办法足以应付各种古里古怪的菜单,而且不光可以用在菜单上,任何需要模样古怪的链接的地方都可以用上它。不过这还不是最完美的方法,还有更棒的。

  我们先把两张背景图合成一张(bk03.gif):

  

  再修改CSS(这里只列出修改了的部分):

menu a{
	...
	background:transparent url(i/bk03.gif) 0 0 no-repeat;
}
menu a:link,menu a:visited{
	background:transparent url(i/bk01.gif) 0 0 no-repeat;
}
menu a:hover,menu a:active{
	background:transparent url(i/bk02.gif) 0 0 no-repeat;
	background-position:0 -21px;
}

  查看效果(例13)

  看明白了吗?事实上只用了一张图,当鼠标覆盖事件产生后把图的位置向上移动了一段距离,刚好露出下半张图的红色背景部分。这样做有什么好处吗?

  1. 方便管理背景图。一个大型网站很可能需要使用几十上百张背景图,把相关的背景图合在一起可以极大地方便管理和维护。
  2. 与桌面软件皮肤的制作方式更接近。制定中的CSS3已经引入桌面软件皮肤制作中最基本的“九宫格”技术,由此网页UI设计已经明显地呈现出向桌面软件UI设计靠拢的趋势。
  3. 节约网络流量。以上面这个例子为例,小的背景图0.47K,合并后的背景图0.94K。两张小图的体积之和也是0.94K,这有什么节约的?我们知道数据是以“IP包”的形式在网络上传输。大部分的IP包都在1K左右,比如我的网站服务器收发的每个IP包大小为1024字节。每张图至少需要一个IP包传输,这么一来两张小图就占用了2K的流量,而使用一张大图只需要1K的流量。对于中小型网站这点流量的出入并不算什么,但对于日访问量上千万的网站来说,“能省则省”并不仅仅是网络流量的问题,而是实实在在的经济问题,不可不重视。
文字替换技术

  某些时候我们对菜单项的视觉效果会要求得更多,比如没有文字纯粹是一张图,或者使用一种极少见的字体。也许你会说:我知道,用背景图片。没错,用上面的“背景图翻转技术”你可以实现它。但是a元素中的文字呢?不能让它继续出现在视野中了,这时就需要用到“文字替换技术”。

  为了方便说明,拿我最喜欢的“百事”和“乐事”做一个简单的菜单:

<menu>
<li id="miLays">
  <a href="http://www.lays.com/" title="乐事薯片">Lay's</a>
</li>
<li id="miPepsi">
  <a href="http://www.pepsi.com/" title="百事可乐">Pepsi</a>
</li>
</menu>

  然后使用“背景图翻转技术”把下面这张图作为背景。

  查看效果(例14)。具体的实现代码请自己查看源文件,用到的技术上面都有提到。

  接下来就是重头戏了:把那两行带下划线的难看文字去掉。让我们先想想有哪些办法可以把元素从页面上隐去:

  1. display:none。好像太厉害了一点,不光把文字隐藏起来,压根就找不到可以点的链接了……-_-|||
  2. visibility:hidden。嗯,文字没了,链接还在……可惜背景图也没了,枪毙!

  好像灭什么办法了?再次向大家隆重介绍text-indent。看看它是怎么做的(在例14的基础上修改):

menu a{
	...
	text-indent:-9999px;
	text-decoration:none;
}

  查看效果(例15)

  OMG,真佩服第一个想出这法子来的人。让文字负缩进9999px,也就是往左移动9999像素,别告诉我你的显示器有这么大的分辨率^_^。后面那个text-decoration:none是为了防止Firefox出现下划线(不信你可以拿掉它试试)。

  到目前为止IE6、Firefox和Opera都表现完美,可是还没完,你会在IE5下发现根本找不到可点的地方……原来IE5把链接的可点区域和文字一起往左挪到了-9999px处,真是麻烦啊-__-|||。解决的方法倒也不难:用绝对定位(这方法是俺自己找出来的,如有雷同纯属英雄所见略同^_^)。

menu li{
	position:relative;
	...
}
menu a{
	position:absolute;
	top:0;
	left:0;
	...
}

  查看效果(例16)

  这下大家都满意了,这篇文章也到尾声了……

小结

  这篇文章里提到的大部分技术和思想不仅仅可以使用在菜单上,比如“背景图翻转技术”的使用范围就相当广,如果你刚开始学习Web标准,不妨亲手制作一个菜单,熟悉一下这些常用技术。如果你已经有一些Web标准实践经验,请关注这篇文章中提到的各种思想,相信有助于你理解Web标准的目标与责任。如果你是经验丰富的高手,请一定指出这篇文章中的错误和不足,我也是边摸索边总结,估计缺陷不会少。

  最后谢谢关注这篇文章的朋友,空的时候我还会接着写其他《基于Web标准的UI组件》。

  注:说了这么多还不能满意你的菜单要求?那你的菜单还真是有点bt,也许我之前翻译的一篇文章能帮上忙(这篇文章中还提到另一种文字替换技术,虽然我觉得不怎么好)。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值