CSS笔记(一):选择器规范
规范定位元素选择器
从性能上考虑,让浏览器查找尽量少的元素以确定我们想要定位的元素。
- 避免同时使用标签、id、class作为定位一个元素的选择器。 div.main{} × .main{} √
按显示效果看,两种写法是没有任何区别的 。但按照后面的特殊性规则来看前者的权重比后者仅多了1,可以说有些多余。
- 尽量减少选择器层级。#wrap div.main{} × .main{} √
许多人的误区可能是层级写得越多,浏览器匹配越精准,也不易漏掉公共样式,潜意识里认为css选择器是从左往右解析的。但实际上css选择器是
从右往左解析的。层级越多不但没有起到优化作用,反而增加了代码冗余,降低了浏览器性能。
详细解析文章:为什么CSS选择器是从右往左解析
选择器的特殊性
每种选择器都有一个数字值(权重),将规则的每个选择器的值加在一起,计算出规则的特殊性。
特殊性的计算采用一个比较高的基数以确保特殊的选择器(如ID选择器)不会被大量一般选择器(如类型选择器)所超越。[参考《精通css》p27]
特殊性分为四个等级:a,b,c,d
- 行内样式:a=1
- b等于ID选择器的总数
- c等于类、伪类和属性选择器的数量
- d等于类型选择器和伪元素选择器的数量
选择器 | 特殊性 | 权重 |
style="" | 1,0,0,0 | 1000 |
#wrapper #content{} | 0,2,0,0 | 200 |
#content .datePosted{} | 0,1,1,0 | 110 |
div#content{} | 0,1,0,1 | 101 |
#content | 0,1,0,0 | 100 |
p.comment .datePosted{} | 0,0,2,1 | 21 |
p.comment{} | 0,0,1,1 | 11 |
div p{} | 0,0,0,2 | 2 |
p{} | 0,0,0,1 | 1 |
实际应用
举两个例子说明特殊性在实际应用中的重要程度。
1. 第一个举ZXX大佬文章中的一个小栗子
原文:小tip: CSS后代选择器可能的错误认识,先上代码。
css
.red p { color: red; }
.green p { color: green; }
html-1
<div class="red"><div class="green"><p>1. 颜色是?</p></div></div>
<div class="green"><div class="red"><p>2. 颜色是?</p></div></div>
看到这里可能有大部分人不假思索答出第一行文本为绿色第二行是红色。没错我就是这么认为的。但拿到编辑器检测以后发现正确答案是两行文本全部变成了绿色。
接下来我修改html代码css不变又试验了一次。
html-2
<div class="green"><p>1. 颜色是?</p></div>
<div class="red"><p>2. 颜色是?</p></div>
这一次的结果很显然,第一行绿第二行红。那么是什么原因造成这两个截然不同的结果?无非是多了两个重复的类嘛。
实际上,存在多个重复类名的情况下,选择器不会自动匹配定位元素最亲近的祖先元素。也就是说无论 green 和 red 类名写在哪里,写多少个都是无足轻重的。
拿例子来说。.red 和 .green 都是标签p的祖先元素,不能错误地认为 .green 是第一行 p 元素的直接父级就会对其应用 .green p {} 的相应样式。
进一步,在 .red 和 .green 同为 p 祖先元素的基础上,两个选择器对于两个p元素来说是一样的,同样匹配。
这种情况下就需要比较选择器的权重了,通过上面的计算方式,两者的权重都是11(0,0,1,1)。
这样在权重相同的情况下后声明的样式覆盖先声明的样式。如果将css声明顺序颠倒,结果就会全部显示红色。
2. 链接伪类选择器的声明顺序
共有五个链接伪类分别是 a:hover/a:focus/a:active/a:link/a:visited 。刚开始我们使用这些伪类选择器做的最多的事就是去掉或者加上链接a的默认样式下划线。
将未访问和已访问的链接设置text-decoration:none,将鼠标悬停和已经激活的链接设置text-decoration:underline。于是我们可能会这样写样式。
a:hover, a:focus, a:active { text-decoration:underline; } a:link, a:visited { text-decoration:none; }
但是经过测试发现鼠标悬停和激活样式并没有起作用。这就是css规则的层叠性和特殊性引起的。
引用《精通css》中的解释,两个规则具有相同的特殊性(类、伪类、属性选择器的权重相同),后定义的规则覆盖前面的, :link和 :visited样式将覆盖:hover和:active样式。
所以应该将两条规则的次序颠倒过来写,悬停和激活样式才起作用。
刚开始不太懂这句话,后来查了一些资料才明白。
鼠标悬停在链接上时,a:link(未访问状态)和a:visited(已访问状态)必定有一个发生。
假定这个链接未被访问过,鼠标悬停于a链接时,这个a元素同时拥有a:hover和a:link两个规则但最后只能应用一个,应用哪一个呢就由特殊性和层叠性来决定。
a:hover和a:link权重相同,a:link后定义,那就要应用a:link的规则,自然a:hover的样式就无效了。
因此也就有了我们常说到的LoVe HAte原则:link--visited--hover-active。