前台开发从头说起:谈谈CSS选择符
以前我接受了网上不少博文的说法,一直认为学习css的三大最重要问题是:盒模型、定位、浮动。因为这三块的内容决定了css布局的能力。但是通过上一篇日志的分析,xhtml要实现和css的解耦,就要尽量不依赖于css(或者说不要纯粹为了给css预留接口而添加不必要的class和id),那么,在用css布局之前,其实就有一个更紧迫的任务摆在我们的面前——如何将css规则准确应用到目标元素。于是,css选择符的地位在这个前提下就空前的提高了。所以,在开始学习盒模型、浮动、定位之前,有必要回顾一下选择符。
一般稍微接触过css的网页设计人员,都会很快地学会三种css选择符:
- 元素选择符(例如:body 、a 、li )
- ID选择符(例如:#head、#body、#foot)
- 类选择符(例如:.red、.item、.content)
更进一步之后,开始了解到一些进阶的选择符:
- 后代选择符(例如 #head .menu、#foot #copyright)
- 伪类选择符(例如 a:hover、a:link)
以及由这些选择符组合起来形成的综合选择符。实际上css还支持一些更丰富的选择符。但是能够被浏览器广泛支持的其实主要就是上面这几种,其它的选择符在css中往往用来区别处理不同的浏览器,或者用在jQuery一类的框架中。本文就不提了。有兴趣的可以自己在网上查一下,像属性选择符(input[type=’password’]、input[type=’radio’])、直接后代选择符(body > div、 #head > ul)等。
实际上,有了上面列出的五种主要的选择符,通过对它们的组合,已经能够满足我们绝大部分时候的要求了,这也就意味着,相同结构下的元素,父级元素或者祖先元素只要有一点点区别,我们就能够在不借助id或者class的情况下直接访问到。例如:
<ul> <li><a href="#">菜单1</a> <ul> <li><a href="#">菜单1-1</a></li> <li><a href="#">菜单1-2</a></li> <li><a href="#">菜单1-3</a></li> </ul> </li> <li><a href="#">菜单2</a> <ul> <li><a href="#">菜单2-1</a></li> <li><a href="#">菜单2-2</a></li> <li><a href="#">菜单2-3</a></li> </ul> </li> </ul>
这个结构是我在《来自微软的纯css下拉菜单》一文中用到的下拉菜单结构。在那个示例中,没有使用任何的class或者id,但是我们通过不同优先级的元素+后台选择符,对结构中的不同层次的ul、li、a实现了精确定位。如下面的代码:
ul {} li {} ul ul {} ul ul li {} li a {} ul li a {} ul li:hover ul {}
那么,在实际开发中,为什么很多网页设计人员还是离不开多如牛毛的ID和class呢(我要声明一下,我从来没有说完全抛弃id和class,我的观点是他们应该尽量少,并且由文档结构决定而不是由css需要决定)?我觉得有三方面的原因:
第一、xhtml文档结构不合理,通过元素不能体现文档的层次结构。满篇都是div。没有有效利用Hx系列标签和ul、ol、dl等不同含义的列表标签、没有有效利用p、quote、pre等标签。xhtml为我们提供了丰富的标签元素,但是如果我们只会用div,那还不如人家用table来布局的。至少他的table在一定程度上也是文档结构的体现,而满篇嵌套的div,文档结构完全没体现。
第二、css选择符掌握得不够,不善于借助文档结构层次上的细微区别,用不同的组合选择符来区别相似但其实不同的元素。例如上面的下拉菜单结构,有的人就非要用“menu”和“submenu”来区别。
第三、css选择符的优先级不清楚。css是支持继承和覆盖的,什么时候继承,什么时候覆盖。两条规则都对相同元素做出了样式规定而且样式规定重复的情况下,哪一条规则会被应用呢?这些问题不清楚,就没办法充分利用优先级实现规则的覆盖。于是只好每个要应用样式的元素都加上id或者class。关于css选择符的优先级,网上也有很多文章,我就不赘述了。
所以说,如果感觉离不了class,离不了id,那只能说明两个问题——xhtml结构不合理或者css掌握得还不够。我上一篇博文发了以后,有位朋友评论说我没做过前台开发。因为没有class和id,就不能实现css和javascript的分离。实际上,只要是长期深入学习css和javascript的朋友应该都清楚:在结构有差异的情况下,用css选择符就能精确定位某个元素;在结构完全相同的情况下,借助javascript和DOM,同样可以精确定位某个元素。
仍然以上面的下拉菜单列表为例。首先使用 ul a 对父级菜单的链接应用样式,然后用ul ul a就可以精确定位到次级菜单的链接,应用新的样式,对ul a的定义进行覆盖。那么,如果是要精确定位到第二级菜单的第二个元素呢?由于css3的选择符目前还没被广泛支持,而结构又没有差异,不借助javascript有困难了。但是借助于javascript,非常轻松,比如在jQuery中,我们可以用 $("ul ul:nth(2) li:nth(2)”) 或者 $("ul ul”).eq(1).find(“li”).eq(1) 都能得到第二个子菜单的第二个菜单元素。
css和javascript能够自己精确找到网页中的任何一个元素,那么网页自然就不用自己标识自己的每个元素。少了这层负担,我们在设计网页文档结构的时候,自然就可以抛弃一切后顾之忧,那么,xhtml中和结构无关的id和class,还有什么必要存在呢?
去除了不必要的表现元素和属性(font、center、align、height)之后,又去除了不必要的id、class、onclick、onmouseover之类的样式和行为属性,我们的网页源代码尺寸越来越小,抓一个页面下来,少量必要的结构元素之外,剩下的全是链接和内容,这样的网站,搜索引擎能不喜欢吗?
没有了后顾之忧,认清了努力方向,那么下一次我们就来谈谈css的盒模型。