6.3.6 下拉导航
下拉菜单仍然是Web上流行的界面元素,虽然有一些纯Javascript 解决方案,但在禁用Javascript 的浏览器下,它却无能为力。因此,纯CSS的下拉菜单才是最好的选择。
这种技术及其简单,只需把子导航嵌套在无序列表中,并让子导航默认隐藏,然后当鼠标悬停或点击父列表时,再让它显示出来。
本节,在上一节主导航的基础上,添加子导航,来演示下拉导航的制作方法。主导航的样式保持不变,这里只介绍子导航的样式。首先,创建多级导航列表。
<ul class = "mainnav">
<li><a href="#">文件</a>
<ul class = "submenu">
<li><a href="#">新建</a></li>
<li><a href="#">打开</a></li>
<li><a href="#">保存</a></li>
</ul>
</li>
<li><a href="#">编辑</a></li>
<li><a href="#">查看</a></li>
<li><a href="#">收藏夹</a></li>
<li><a href="#">工具</a></li>
<li><a href="#">帮助</a></li>
</ul>
与主导航相同,首先需要重置列表的默认样式,将外边距、内边距设置为 0,并去掉默认的项目符号。
.submenu {
margin: 0;
padding: 0;
list-style: none;
}
由于在主导航中让所有 li 向左浮动,子导航中,需要子导航垂直显示。因此,需要让子导航中的 li 样式不再浮动。
.submenu li {
float: none;
}
接下来,把子导航中链接的 display 属性设置为 block,以便在链接区域的任何位置都能激活链接。再设置链接的宽度、默认属性、以及鼠标悬停时的属性。
.submenu li a {
color: #000;
padding: 4px 0;
font-size: 13px;
display: block;
}
.submenu li a:hover {
color: #fff;
background: #4899E0;
}
子导航样式设置完成后,就可以通过 display: none 把子导航隐藏起来。当鼠标悬停在主导航的 li 上时,再通过 display: block 把子导航显示出来。
.mainnav li:hover .submenu {
display: block;
}
由于子导航在普通流中定位,会占用父元素的空间。因此,如果子导航使用绝对定位,它就会脱离文档流,不再占用父元素的空间。这样的话,在子导航被显示出来时,父元素的高度就不会被撑开。
.submenu {
padding: 0;
list-style: none;
display: none;
position: absolute;
}
至此,纯CSS的下拉菜单就制作完成了,快来看看效果吧!
这里只是演示了二级下拉菜单的制作过程,当然,也可以制作三级、四级,甚至更多级的下拉菜单。假如在二级菜单下,又添加三级下拉菜单:
<li><a href="#">查看</a>
<ul class = "submenu">
<li><a href="#">工具栏</a></li>
<li><a href="#">转到</a>
<ul class = "drop">
<li><a href="#">后退</a></li>
<li><a href="#">前进</a></li>
</ul>
</li>
</ul>
</li>
无论多少级菜单,其本质完全相同,制作方法也没什么差别。都是让子菜单使用绝对定位,并默认隐藏起来,当鼠标悬停在上一级菜单上时,再自动将下级菜单显示出来。
.drop {
left: 100%;
display: none;
list-style: none;
background: #ccc;
position: absolute;
}
.submenu li:hover .drop {
display: block;
margin-top: -27px;
}
添加三级菜单后的运行结果如图 6‑17 所示:
上述这种技术制作出来的下拉导航,可以适用于大多数现代浏览器,但在IE7及以下版本中,存在易用性问题。
一个问题是,在IE7及以下版本中,多级列表中,下级列表的位置会发生偏移,导致二级和三级菜单的位置不正确。可以通过 CSS hack 对二级和三级列表进行修正,偏移的距离,要根据实际情况确定,而IE6与IE7偏移的距离可能会不同,需要单独修正。
.mainnav li:hover .submenu {
display: block;
*margin-top: 38px;
*margin-left: -88px;
_margin-top: 40px;
_margin-left: -84px;
}
.submenu li:hover .drop {
display: block;
margin-top: -27px;
*margin-top: 0;
*margin-left: 0;
}
另一个问题是,在IE6中,当鼠标悬停在主导航的 li 上时,子导航却不能正常显示出来,因为IE6不支持在非锚元素上使用 :hover 伪类选择器。因此,需要使用 Javascript 或 .htc 文件来启用这个功能。
.htc 文件实际上就是脚本文件,只有IE能够识别它。 在网上下载csshover.htc 文件,把它放在网站的某个位置,然后,在 body 选择器中通过 behavior 属性指向该文件即可。
body {
behavior: url("http://XXX/csshover.htc");
}
还有一个问题,就是上述每个 li 后面有一个回车,在IE6中,当 li 中的内容是一个 a 元素,并且 a 元素或 a 元素的子元素(如,<img/>元素)设置了display: block 时,浏览器将不会忽略 li 之间的空白字符,表现为在 li 之间有一个额外的空行。
这个问题有两种解决办法:一种方法是避免为 li 中的 a 元素或 a 元素的子元素设置display: block,或去掉 li 后面的回车;另一种方法是就是让 a 元素或 a 元素的子元素触发布局,常用的就是通过 _zoom: 1 触发布局,因为它没有副作用。
我们使用第一种方法,让二级、三级等列表中的链接使用display: inline-block,这样既不影响链接的点击区域,又可以消除 li 之间的额外空行,可谓一举两得。
.submenu li a {
color: #000;
font-size: 13px;
padding: 4px 0;
display: inline-block;
}
至此,我们的三级下拉导航才算真正制作完成,它在所有的浏览器下都表现正常,并且表现完全一致。