作为前端多多少少都会对CSS样式的权重有一定的了解。最常用的方法就是对不同的选择器分配不同的权重比,常见的就是
选择器 | 权重值 |
---|---|
!important标识 | 10000 |
行内样式 | 1000 |
id选择器 | 100 |
类选择器 | 10 |
标签选择器 | 1 |
通配符 * | 0 |
具体的判断我们可以用一个矩阵来表示:(0, 0, 0, 0, 0)。那这里面的每一个矩阵的0表示的是
- 第一个:
!important
的个数 - 第二个:行内的个数
- 第三个:id选择器的个数
- 第四个:类选择器的个数
- 第五个:标签选择器的个数
行内除了!important
高于其他的样式。同时,这里的这个矩阵实际上是不存在的,是认为的构建出来的。因为!important
始终最高,所以这里可以忽略第一个,最后矩阵为(0, 0, 0, 0)。
上面表格中是我们在写css样式的时候需要了解最的基本的知识,也是最为普通的选择器权重分配。权重值越高,权重越高,那么样式的优先级就越高。所以,!important
的权重是最高的。正式因为这一点,所以!important
在编写css样式的时候一般都不建议使用,因为使用了!important
后,要想在修改样式,几乎是不可能的,即,样式会变得不好控制。
其次是行内样式。在现在前端开发中,为了更好的阅读代码,是代码调理更清晰,一般都会把CSS代码以及JS代码从HTML中分离,采用外链的方式引入CSS以及JS。所以,行内样式在一般的开发中,用的也不多。但是,在使用前端三大框架或者是需要使用JS来控制样式的时候,多多少少的都会涉及到把样式写在HTML元素行内的情况。
接着是ID选择器。在编写样式的时候,我们一般都不会使用ID选择器来控制样式,同时也不会在HTML文档中添加过多的ID选择器。ID选择器一般更多的是用于获取元素,而不是用来控制CSS样式。
再者是类选择器。这个在CSS样式的编写中用的算是最多的一种,因为一个标签可以添加多个类名,不像ID只能添加一个,编写不同的类名来控制不同的样式显示,同时根据权重来控制样式的覆盖。
然后是标签选择器,这个在开发中也是不建议使用,更多的是建议添加一个类名来控制,以实现复用,同时方便控制。
最后是通配符选择器,这个选择器的使用一般就是初始化文档结构。例如
1 | * { |
但是更多的公司采取的是具有针对的样式重置,比如reset.css。
以上就是常用的样式选择器以及他们的权重。
主要选择器的权重比较
权重累加
上面的权重值我们已经知道了,那么具体怎么来算呢?个人认为,需要记住一这点就OK了。相同类型的权重值累加,然后在比较相同类型选择器的值
。举个🌰
1 | <div id="box" class="box div"></div> |
1 | div { |
上面的代码中,来看看这个div盒子的颜色应该是什么呢?分析一下CSS样式:
根据上面的矩阵(0, 0, 0, 0)来分析。
#div
的矩阵为(0, 0, 1, 0, 0),最后的权重值为:1*100 = 100。
div.div
的矩阵为(0, 0, 0, 1, 1),最后的权重值为:1 * 10 + 1 *1 = 11。
所以最后的样式显示 background: green;
有了这样的结论,我这里又做了一个测试。有下面的一段html代码与样式
1 | <div class="box"> |
1 | div { |
按理说 #box10
的权重为 100 * 1 = 100
.box .box1 .box2 .box3 .box4 .box5 .box6 .box7 .box8 .box9 .box10
的权重为 10 * 11 = 110
下面使用多个类的权重值理论上是高于上面只使用一个id选择器的情况,但是最后的结构却不是我们想象的那样。结果还是 green 。没错,后面的11个类的样式无效。经过这样的测试,我们可以猜想,在一个元素使用了ID选择器修饰了样式以后,如果在使用类选择器,这时候是是没有办法使相同的样式属性生效,生效的依然是那个ID选择器修饰的样式。为什么权重值大也没有用呢?我猜或许是因为写了太多类名的时候再和ID相比的话,浏览器会自己去判断,选择最优的那个,毕竟10多个类名在实际的开发中是不存在的。在张鑫旭大神的有趣:256个class选择器可以干掉1个id选择器有一个实验,但是这个实验室在2012年的时候,那个时候,还是使用的IE浏览器能够呈现出来。但是现在大部分的浏览器都不能够呈现出256个class干掉一个id的情况了。同时,也证明了,上面我们定义的矩阵(0, 0, 0, 0)其实并不严谨,id与class之前的差距我们这里以10作为一个标准,但是实际上可能达到100,或者1000。即1000个class干掉一个ID。但是由于现代编码一般要求class的层级书写的时候不要超过四层,所以,目前这个问题也就没有什么意义了。
因此,上面的矩阵也可以作为我们判断的标准。
其他类型选择器的权重比较
上面说了几种常用的选择器了,但是还有一些选择器也是在开发中会出现,但是不是太常用的一些选择器。那么,有哪些呢?
w3c中样式选择器的权重优先级的排序如下
important > 内嵌样式 > ID > 类 | 伪类 | 属性选择 > 标签 | 伪元素 > 伪对象 > 继承 > 通配符 | 子选择器 | 相邻选择器
- 伪类选择器,如
:hover
- 属性选择器,如
[type="text"]
- 伪元素选择器,如
::first-letter
- 子选择器
>
,相邻兄弟选择器+
等等
伪类的优先级(:)
首先来看看伪类选择器的优先级。
1 | <head> |
上面的代码在codePen中的具体效果,可以看到
当将鼠标分别移动到两个div盒子上面的时候,前面的绿色盒子的背景色会发生变化,而红色盒子不会。但是,都是 :hover
的一盒伪类。所以判定,伪类的权重与类的权重是相同的。
属性选择器的优先级
同样是上面的代码,我们把样式改为
1 | div { |
唯一不同的就是样式中添加了属性选择器[class="box1"]
与[class="box2"]
。同时顺序发生了改变。
代码可看[https://codepen.io/Anthony-Wilson/pen/YzKWZpL]https://codepen.io/Anthony-Wilson/pen/YzKWZpL
。
所以,属性选择的权重 = 类的权重 = 伪类的权重。三者是相等的,都是(0, 0, 1, 0);
伪元素选择器(::)
伪元素作为一种特殊的存在,我认为它不应该放在优先级里面同其他的选择器相比。比如 ::before
和 ::after
这两种伪元素都是在文档中添加一个假的元素,并不能够设置 id class 等属性。所以这里可以把它作为一个唯一的存在。那么他的权重我们可以看为1。同时没有和他比较的。
子选择器>
,相邻兄弟选择器+
1 |
|
上面的例子在codePen中的运行结果
可以看到,第一个我是蓝色,第二个我是红色。结合上面的代码,可以看出来子元素选择器和普通的空格其实没有太多的区别,同理兄弟选择器其实也是一样的。遇到这种情况,直接比较 class 与 标签的个数就可以了。即同基本的权重判断是相同的。
结果总结
经过上面的推想测试,可以大致的得出一个优先级的结论:
!important > ID > class = 属性 = 伪类 > 标签 > 通配符 > 继承 > 浏览器自带属性
在使用选择器的时候尽可能的选择使用 class选择器或者属性选择器(针对于input这一类)来对元素设置样式。一个是使用class可以复用,第二个可以更好的控制元素样式。同时,关于class命名的规范建议使用BEM命名规范。
补充:2019年08月22日
在网上看到这样的一道题
问题:已知如下代码,如何修改才能让图片宽度为 300px ?注意下面代码不可修改。
<img src=”1.jpg” style=”width:480px!important;”>
期初看到这段代码一下子就想到这都 !important
了还有办法限制它的宽度?真的是被无知限制了想象力。
这里提供几种方法实现修改宽度:
1、使用max-width
虽然使用了 important
,但是也只是添加到了 width
属性上面,并不影响 max-width 。所以这里设置了 max-width 即可生效。
1 | img { |
2、使用 transform:scale
1 | img { |
3、使用 zoom
这个和CSS3的缩放是一样的效果
1 | img { |
4、使用 js
这个和CSS3的缩放是一样的效果
1 | document.getElementsByTagName("img")[0].setAttribute("style","width:300px!important;") |
5、使用弹性盒模型
这个和CSS3的缩放是一样的效果
1 | img { |
6、使用animation
1 | img { |