好久没玩CSS布局了,对于大多数在已有Web框架上开发项目的童鞋,极少情况会用到CSS来布局和美化页面。比如我现用所在项目用的是公司的一个现有Web框架+ExtJs库,对CSS仅仅是一些像给某个元素换背景图之类的简单的应用。今天在博客园闲逛,无聊看了一下博客园首页左侧的网站导航的代码,然后我觉得应该有更好的实现方式(至少我认为)。博客园之所以现在的方式实现左侧导航,估计是为了更好的与后台业务结合吧。
当我们要实现一个功能时,往往有很多解决方式,有些好的方式也往往很难分出绝对的优劣。对于一个功能的实现,如果你试图去寻找一种最优的解决方案,那可能是一种无穷无尽的工作,而现实工作中我们也不可能花太多的时间去寻找更多更佳的解决方案。这种“程序员精神”的“寻找”工作只能作为我们平时闲的无聊时的一种消遣。如果此时你正好也很闲,不访和我一起探讨探讨网站左侧导航的实现。虽然实现起来很简单,但你的方式是不是一定是最佳的呢?
废话不多说,让我们先来看看博客园的实现吧。为了把重点放在CSS上,我对博客园的代码进行了一些改变,但大体逻辑是一样的(感兴趣的话可以查看博客园的前台代码)。
HTML部分(后台生成):
<div id="cate_wrap"> <div id="cate_title_wrap"> <i id="cate_title_img"></i> <b> 网站分类</b> </div> <ul id="cate_item"> <li id="cate_item_20">.NET技术(9)</li> <li id="cate_item_50">编程语言(7)</li> <li id="cate_item_80">软件设计(0)</li> ... </ul> <ul id="cate_sub_20" class="cate_sub_wrap"> <li>.NET新手区(0)</li> <li>ASP.NET(2)</li> <li>C#(4)</li> <li>WinForm(1)</li> <li>Silverlight(0)</li> <li>WCF(0)</li> <li>CLR(0)</li> <li>WPF(6)</li> </ul> <ul id="cate_sub_50" class="cate_sub_wrap"> <li>Java(3)</li> <li>C++(2)</li> <li>PHP(2)</li> <li>Delphi(0)</li> </ul> <ul id="cate_sub_80" class="cate_sub_wrap"> <li>架构设计(0)</li> <li>面向对象(3)</li> <li>设计模式(0)</li> </ul> </div> |
CSS部分:
/*一些全局设置*/ html, body,div, ul, li { margin:0; padding:0; } ul{ list-style:none; } a { color:#666; text-decoration:none; }
/*左边导航*/
#cate_wrap { position: absolute; left: 10px; top:
50px; width: 160px; padding-top: 0px; }
#cate_wrap a { text-decoration:none;}
#cate_title_wrap { height:20px;padding-left:8px;background-color:#009900;color:#FCFCFC;cursor:default;}
#cate_item {border:1px solid #ababab; background-color:#FFF;
}
#cate_item li { cursor:pointer; height: 30px;
line-height: 30px; border-bottom: 1px solid #ababab;
padding-left: 8px;background: url(arrow.png);
}
#cate_item li.over{ color:#FFF;background-color:
#FF9320;}
.cate_sub_wrap {cursor:pointer; position: absolute;
left: 148px; display: none; width: 150px; border:
1px solid #ababab;border-bottom:2px solid #ff8500;
line-height: 2em; background-color:#FFF; }
.cate_sub_wrap li { padding-left: 10px; height:
28px;border-bottom:1px solid #ababab; }
.cate_sub_wrap li.over{ color:#FFF;background-color:
#FF9320;} |
JS部分(博客园是把mouseover和mouseout的调用放在html中,这里我放在JS中动态绑定,区别不大):
$(function () { //给第一级分类添加mouseover、mouseout效果 $("#cate_item li").mouseover(function () { //通过截取id数字部分动态控制子分类的wrap块显示位置 var top = $(this).addClass("over").attr("id").substr($(this).attr("id").lastIndexOf('_')+1); $("#cate_sub_" + top).show().css("top", top + "px");
}).mouseout(function () {
var top = $(this).removeClass("over").attr("id").substr($(this).attr("id").lastIndexOf('_')
+ 1);
$("#cate_sub_" + top).hide();
});
//这里还需要给子分类的wrap块添加mouseover、mouseout事件,控制当前的第一分类的显示效果
$(".cate_sub_wrap").mouseover(function
() {
var top = $(this).attr("id").substr($(this).attr("id").lastIndexOf('_')
+ 1);
$("#cate_item_" + top).addClass("over");
$(this).show().css("top", top + "px");
}).mouseout(function () {
var top = $(this).attr("id").substr($(this).attr("id").lastIndexOf('_')
+ 1);
$("#cate_item_" + top).removeClass("over");
$(this).hide().css("top", top + "px");
});
//给第二级分类添加mouseover、mouseout效果
$(".cate_sub_wrap li").mouseover(function
() {
$(this).addClass("over");
}).mouseout(function () {
$(this).removeClass("over");
});
}); |
效果图:
代码很简单,不需要作解释。主要是让大家了解一下这种思路。下面用另一种方式实现,这个过程我尽量讲的详细一点。
一步一步来,用VS先创建一个html文件,在body元素中添加一个div层,如下:
<body> <div id="cate_nav_wrap"> </div> </body> |
接下来用jQuery模拟后台动态创建“网站分类”html的ul和li元素,如下:
$(function () { //动态创建用于网站导航的ul、li元素 var $ul = $("#cate_nav_wrap").append("<ul id='cate_nav'></ul>").children("ul"); for (var i = 0; i < 10; i++) { var $sub_ul = $ul.append("<li></li>").children("li").eq(i).append
("<a href='#'>第一级分类" + i + "</a><b>></b>").append("<ul></ul>").children("ul"); for (var j = 0; j < 6; j++) { $sub_ul.append("<li></li>").children("li").eq(j).append("<a href='#'>
第二级分类" + i+j + "</a>"); } } }); |
上面的jQuery代码会生成如下html元素:
<div> <ul id="cate_nav"> <li><a href="#">第一级分类0</a><b>></b> <ul> <li><a href="#">第二级分类00</a></li><li><a href="#">
第二级分类01</a></li><li><a href="#">第二级分类02</a> </li> <li><a href="#">第二级分类03</a></li><li><a href="#">
第二级分类04</a></li><li><a href="#">第二级分类05</a> </li> </ul> </li> <li><a href="#">第一级分类1</a><b>></b><ul> <li><a href="#">第二级分类10</a></li><li><a href="#">
第二级分类11</a></li><li><a href="#">第二级分类12</a> </li> <li><a href="#">第二级分类13</a></li><li><a href="#">
第二级分类14</a></li><li><a href="#">第二级分类15</a> </li> </ul> </li> <li><a href="#">第一级分类2</a><b>></b><ul> <li><a href="#">第二级分类20</a></li><li><a href="#">
第二级分类21</a></li><li><a href="#">第二级分类22</a> </li> <li><a href="#">第二级分类23</a></li><li><a href="#">
第二级分类24</a></li><li><a href="#">第二级分类25</a> </li> </ul> </li> ... ... </ul> </div> |
为了达到和博客园类似的导航效果,我们一般会这样定义CSS:
body,div, ul,a { margin: 0px; padding: 0px;font-size:12px; } a { text-decoration: none;} ul { list-style: none; width:150px;background-color:#fff;border: 1px solid #808080; border-bottom: none;} #cate_nav_wrap { position: absolute; top: 100px; left: 10px; } #cate_nav li {cursor:pointer; border-bottom: 1px solid #808080;
padding-left: 10px;height:30px;line-height:30px; } #cate_nav li b{ margin-left:55px;}/*">"箭头样式*/ #cate_nav li ul { display: none; position:absolute; left:150px;} #cate_nav li.over { background-color: #0094ff; color: #fff; }/*元素被mousemove的样式*/ |
到这里,我们来看一下效果:
这个时候鼠标移上去当然是没有效果的,因为我们还要加入下面这样一段jQuery代码:
//添加mousemove、mouseout显示效果 $("#cate_nav li").mousemove(function () { //这里需要计算第二级分类ul块的显示位置 $(this).addClass("over").children("ul").show().css
("top", $(this).index() * 30 + $(this).index() + "px"); }).mouseout(function () { $(this).removeClass("over").children("ul").hide(); }); |
好,我们再来看一下效果:
但是似乎有个问题,当鼠标移动分类上的时候,文字的颜色并没有反色显示(显示为白色#fff,这也是一种常见效果),因为我们在CSS中已经定义了这样一段样式:#cate_nav
li.over { background-color: #0094ff; color: #fff; }。明明定义了当mouseover的时候反色显示,为什么没效果呢?
原因很简单,因为文字是包裹在<a>元素里的,系统给<a>元素的color属性设置了blue,他父级元素<li>的属性优先级要低于<a>自身的属性,所以<li>的color属性对<a>是不起作用的,而<li>元素下面还有一个<b>元素,它是没自己的color属性的,所以鼠标移到分类上时有反色显示。因此,我们自然就有了解决<a>标签没有反色显示的办法,自然会想到,当moseover的时候再控制一下<a>的样式不就行么。于是我们去掉
#cate_nav li.over { background-color: #0094ff; color:
#fff; } 中的color属性,加上这样一句CSS代码:
#cate_nav li a.over { color: #fff; } |
JS也要做相应的变动:
//添加mousemove、mouseout显示效果 $("#cate_nav li").mousemove(function () { //这里需要计算第二级分类ul块的显示位置 $(this).addClass("over").children("ul").show().css
("top", $(this).index() * 30 + $(this).index() + "px"); $(this).children("a").addClass("over"); //新增加部分 }).mouseout(function () { $(this).removeClass("over").children("ul").hide(); $(this).children("a").removeClass("over");//新增加部分 }); |
看看是不是有了我们想要的效果:
OK,和我们想的一样,效果出来了。我们总共加了三行代码,CSS一行,JS两行,另外去掉了一个color属性。有没有一行也不加或只加一两句代码也实现同样的效果呢?
答案是肯定的。如果你对编写代码有洁癖,那么你一定会为把“增加三行代码”变成“增加两个属性”而感到高兴,接下来就让你高兴一把。让我们回到分类文字没有反色显示的位置,把刚刚增加的三行代码去掉,还原刚刚去掉的color属性。先讲一下思路:
首先我们要解决的问题是文字没有反色显示,也分析了问题的原因。根据前面的分析, 要做到尽可能少改动代码,甚至JS代码一点也不用改,我们只能在CSS代码上下功夫了。第一,要想办法去掉系统给<a>自带的color属性,手动给<a>元素定义一次color属性。第二,这个color属性值不能和<a>是直属关系,color的属性值和<a>必须是一种间接关系。
于是我们可以这样做:把CSS代码的 a { text-decoration:
none;} 部分增加一个color属性,变成 a { text-decoration: none;color:inherit;}
,让<a>元素的color属性继承父级的color属性。由于我们已经对mouseover的元素<li>增加了样式:.over
{ background-color: #0094ff; color: #fff; } , 这样当鼠标移到分类条目上时,它的字体颜色应该会显示成<li>定义的#fff(即白色)。我们来看一下是不是这样,效果是:
这显然不是我们想要的效果,当鼠标移到“第一级分类1”时,他的子分类的文字也全部变成白色了。这是因为因为第一级分类<li>元素的后代不仅包含第一级分类的<a>标签,还包含第二级分类的<a>标签。刚刚我们已经增加了<a>元素的color属性,根据上面的思路,我们还需要定义一下比第一级分类<li>元素更高优先级的color属性,这样第二级分类的文字颜色就不会承着第一级分类的文字颜色变化了。第一级分类<li>元素下面有<ul>元素和<li>元素,这里我们给第一级分类<li>元素下面有<ul>元素增加color属性,即把CSS代码的
#cate_nav li ul { display: none; position:absolute;
left:150px;} 变成了:
#cate_nav li ul { display: none; position:absolute; left:150px;color:#000;} |
再来看一下效果:
OK,没问题。这样,我们只增加了CSS的两个color属性,JS代码完全没有动,也达到了我们要的效果。
其实我觉得上面代码还可以继续缩减,像我开篇所说,我对CSS也只是个了解的程度,平时开发极少用到CSS,更不用说这方面的实际开发经验。相信在博客园有很多这方面的高手,也有很多有这方面的经验的人,希望这些们不吝赐教,全当是把代码娱乐消遣化,这样才更能激发我们对编程更深厚的兴趣,不是吗。
为了让大家方便copy整个代码继续研究,下面贴上整个html文件的代码:
<!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title></title> 6 <style type="text/css"> 7 body, div, ul, a { margin: 0px; padding: 0px; font-size: 12px; } 8 a { text-decoration: none; color: inherit; } 9 ul { list-style: none; width: 150px; background-color: #fff;
border: 1px solid #808080; border-bottom: none; } 10 #cate_wrap { position: absolute; top: 100px; left: 10px; } 11 #cate_nav li { cursor: pointer; border-bottom: 1px solid #808080;
padding-left: 10px; height: 30px; line-height: 30px; } 12 #cate_nav li b { margin-left: 55px; } 13 #cate_nav li ul { display: none; position: absolute; left: 150px; color: #000; } 14 #cate_nav li.over { background-color: #0094ff; color: #fff; } 15 </style> 16 <script src="script/jquery-1.4.2.min.js"></script> 17 <script type="text/javascript"> 18 $(function () { 19 //动态创建用于网站导航的ul、li元素 20 var $ul = $("#cate_wrap").append("<ul id='cate_nav'></ul>").children("ul"); 21 for (var i = 0; i < 10; i++) { 22 var $sub_ul = $ul.append("<li></li>").children("li").eq(i).append("<a href='#'>
第一级分类" + i + "</a><b>></b>").append("<ul></ul>").children("ul"); 23 for (var j = 0; j < 6; j++) { 24 $sub_ul.append("<li></li>").children("li").eq(j).append("<a href='#'>
第二级分类" + i + j + "</a>"); 25 } 26 } 27 //添加mousemove、mouseout显示效果 28 $("#cate_nav li").mousemove(function () { 29 $(this).addClass("over").children("ul").show().css
("top", $(this).index() * 30 + $(this).index() + "px"); 30 }).mouseout(function () { 31 $(this).removeClass("over").children("ul").hide(); 32 }); 33 }); 34 </script> 35 </head> 36 <body> 37 <div id="cate_wrap"> 38 </div> 39 </body> 40 </html> |
在Firefox下,上面代码被 HolyKnight 发现有bug ,为了解决在Firefox下的兼容性问题,对JS进行了修改,我暂时只能这样改,不知道朋友们有没有更优的解决办法,下面是我修改后的完整代码:
复制代码 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style type="text/css"> body, div, ul, a { margin: 0px; padding: 0px; font-size: 12px; } a { text-decoration: none; color: inherit; } ul { list-style: none; width: 150px; background-color: #fff;
border: 1px solid #808080; border-bottom: none; } #cate_wrap { position: absolute; top: 100px; left: 10px; } #cate_nav li { cursor: pointer; border-bottom: 1px solid #808080;
padding-left: 10px; height: 30px; line-height: 30px; } #cate_nav li b { margin-left: 55px; } #cate_nav li ul { display: none; position: absolute; left: 140px; color: #000; } #cate_nav li.over { background-color: #0094ff; color: #fff; } </style> <script src="script/jquery-1.4.2.min.js"></script> <script type="text/javascript"> $(function () { //动态创建用于网站导航的ul、li元素 var $ul = $("#cate_wrap").append("<ul id='cate_nav'></ul>").children("ul"); for (var i = 0; i < 10; i++) { var $sub_ul = $ul.append("<li></li>").children("li").eq(i).append("<a href='#'>
第一级分类" + i + "</a><b>></b>").append("<ul></ul>").children("ul"); for (var j = 0; j < 6; j++) { $sub_ul.append("<li></li>").children("li").eq(j).append("<a href='#'>
第二级分类" + i + j + "</a>"); } } //添加mousemove、mouseout显示效果 $("#cate_nav>li").mousemove(function () { $(this).addClass("over").children("ul").show().css
("top", $(this).index() * 30 + $(this).index() + "px"); }).mouseout(function () { $(this).removeClass("over").children("ul").hide(); }); $("#cate_nav>li ul").mouseover(function () { $(this).show().parent("li").addClass("over"); }).mouseout(function () { $(this).hide().remove("over"); }); $("#cate_nav>li ul li").mousemove(function () { $(this).addClass("over"); }).mouseout(function () { $(this).removeClass("over"); }); }); </script> </head> <body> <div id="cate_wrap"> </div> </body> </html>
|
|