CSS样式权重
前言
CSS 样式权重
CSS 样式权重
之前做的两个项目,写一些组件时会出现样式无法覆盖的情况,所以写写,来增加理解。
CSS 中的样式有一套规则,来判断样式的权重,对一个元素,权重最大的生效,也就是其他的样式都此样式被覆盖。
对于权重,分了几个等级,依次递减为。
!important
此样式的权重最高,为1|0|0|0|0
;style="..."
内联样式,此样式权重次高,为1|0|0|0
;#idname
id 选择器,此样式权重次次高,为1|0|0
;.classname
|:hover
|input[disable]
类选择器,伪类选择器,属性选择器,此样式权重次次次高,为1|0
;h1
|::after
标签选择器,伪元素选择器,此样式权重倒数第二,为1
;*
|+
|~
|>
|:not
通用选择器,相邻选择器,同胞选择器,子选择器,以及否定伪类,此样式权重最低,为0
,即这几个不参与样式权重的计算。
!important
每次当我不知道为啥无法覆盖当前的样式时,我就会使用此来覆盖样式 😂。
不过这样做并不好,因为写不出覆盖效果大概率是没懂 css 的权重计算,理解了并使用才是最好的。
给某个 css 属性值末尾加上!important
之后,那么这个样式的优先级就变得最高了,无论是先写还是后写(对于权重相同的样式,后写的会覆盖先写的)。
1 | <div class="div1" style="background-color: pink!important;"></div> |
1 | div { |
效果图
发现写在内联的样式中的!important
背景色覆盖了类名.div1
的样式
不过这么些并没有什么说服力,因为刚开始我们就说内联样式权重是大于类名样式权重的。
所以内联样式就是会覆盖类名样式的
所以我们换个思路
1 | <div class="div1" style="background-color: pink;"></div> |
1 | div { |
我们在类里面使用!important
设定背景色,然后在内联样式中也设定背景色。
按照之前的排行,内联样式是会覆盖类名样式的。
我们不加!important
看看效果。
图中展示确实是内联覆盖了类名。
然后我们在类名中加上!important
,看看效果。
类名的样式覆盖了内联样式了,有点意思 😏。
当然这里的覆盖只会应用于背景色这个样式,其他没设置的依然是内联覆盖类名的。
1 | <div |
1 | div { |
效果图
内联的高度和宽度还是覆盖了类名的,只有背景色background-color
是类名覆盖内联的,因为加上了!important
。
前面说过,有几种选择器是不参与权重计算的,他们的权重为0
。
那么我们试试如果把!important
写到这些选择器里面会是什么效果,就以通用符*
来作例子。
1 | <body></body> |
1 | * { |
按照前面的说法,如果*
不参与权重计算,那么页面应该是白色,但是在*
里面使用!important
之后。
整个页面都变成蓝色了,也就是!important
覆盖了标签名的样式。
style="..."
内联样式大部分的时候都是在想动态的计算 css 属性值时才会使用。
像 Bilibili 首页的轮播图就是使用了内联的transform
来动态的控制translate3d
中水平 X 坐标的位置(第一个参数)。
内联样式是仅次于!important
的,优先级很高,但是很多的时候都不会写大量的内联样式。
内联 VS ID
1 | <div id="div1" style="background-color: pink;"></div> |
1 | div { |
效果图:
内联的粉色覆盖了id
的蓝色。
内联 VS 类名
1 | <div class="div1" style="background-color: pink;"></div> |
1 | div { |
效果图:
内联的粉色覆盖了类名的蓝色。
内联 VS 标签
1 | <div style="background-color: pink;"></div> |
1 | div { |
效果图:
内联的粉色覆盖了标签的蓝色。
#idName
id 选择器,怎么说呢,我做的两个项目都只在根上使用了 id 选择器,主要是设置字体大小和颜色等一些基本的样式。
id 选择器的优先级次于!important
和内联。
ID VS 类名
1 | <div id="div1" class="div"></div> |
1 | div { |
效果图
ID 的粉色覆盖了类名的蓝色。
ID VS 标签
1 | <div id="div1"></div> |
1 | div { |
效果图
ID 的粉色覆盖了标签的蓝色。
.className
类名选择器,这个可以说是最常用的了,一般不会写很多内联,也不会写很多 id 选择器,而是通过类名来分组,通过类的名字来表示类的作用。
之前在做学校新的官网的时候,使用了一点’语义化’的css
(应该可以这么比喻)。
项目中很多地方使用了flex
布局,以及间距等,所以写了一些公共的样式来直接的使用,比如:
1 | .mt-10 { |
总体而言效果还不错,可能是项目比较小的缘故 🤣。
类名 VS 标签
1 | <div class="div1"></div> |
1 | div { |
效果图:
如何计算权重?
前面我么写的都是些简单的比较,而实际上可能我们的选择链会很长,比如:
1 | .button .button__icon .button__icon--color { |
那么应该如何计算选择链条的权重呢?
前面已经把每种选择器的权重都写出来了,比如对于下面这个选择链:
1 | li > a[href="#achor1"] > .inline-warning { |
我们可以根据之前的说明,发现这个里面存在了两个标签选择器li
和a
。
此时的权重应该是0|0|0|0|2
。
接着又发现了里面存在一个类选择器.inline-warning
和属性选择器[href="#achor1"]
。
此时的权重应该是0|0|0|2|2
。。
由于直接子元素选择权重为 0,所以无需计算。
所以此时的权重为0|0|0|2|2
。
那么此时如果出现了另一个选择器,为如下:
1 | #l1 > a[href="#achor1"] > .inline-warning { |
那么同样根据计算,这个的权重应该为0|0|1|2|1
。
那么此时下面这个的权重是大于上面那个的,可以实验一下。
1 | <ul> |
1 | #l1 > a[href="#achor1"] > .inline-warning { |
效果图
发现使用 id 选择器开头的覆盖了使用标签开头的。
OK,权重大的覆盖权重小的,完全没什么问题,但是如果两者权重相同呢?
比如下面这两个选择链
1 | <div class="div1"> |
1 | .div1 > span > .icon { |
这两个选择链都是两个类选择器和一个标签选择器,所以权重是一样的,都是0|0|0|2|1
效果图
发现后面一个样式链生效了,难道是先写类名的权重高吗??
不急,我们调换 css 的书写顺序
1 | .div1 > .span > span { |
效果图
发现变成红色了。
其实没有那么的复杂,由于权重相同,所以后写就会覆盖先写的,就是这么的简单。
注意点
权重计算
网上比较多的文章以 10000
,1000
,100
,10
,1
来表示每类的权重,并通过相加来计算权重。
这么做其实有个问题,那就是权重它并不是按10
进1
的,也就是说:
1000 个标签选择器也比不过 1 个类选择器。
比如
1 | div > div > div > div > div > div > div > div > div > div > div { |
如果按照上面权重相加来计算的话。
此时第一条的权重为00011
,第二条为00010
。
那么应该显示红色才对。
但其实是显示的蓝色 🤣。
所以我在写的时候,用了一个|
来隔开,只要单纯把每个位置当成计数位,而不是通过相加,即:
第一条权重应该为0|0|0|0|11
。
第二条权重应该为0|0|0|1|0
。
所以就不会出现相加误判的情况了。
!important
网上有些帖子!important
为绝对的优先,后面的覆盖前面。
其实它也是可以计算出权重的,而权重会影响到覆盖的。
比如下面两个带!important
的样式应该是哪个覆盖哪个。
1 | #d1 > .div { |
按照绝对优先的说法应该是显示红色的
但其实是蓝色,也就是上面的权重大于下面,下面的无法覆盖上面
第一个的权重1|0|1|1|0
第二个的权重1|0|0|1|0
第一个权重大于第二个,所以显示第一个。
这也引申出了如何去覆盖一个定义的!important
样式,
比如它在一个标签上定义了
1 | h1 { |
那么此时想要覆盖,就得使得权重比上面这个大,上面这个的权重为1|0|0|0|1
比如可以写一个权重为1|0|0|0|2
的,比如
1 | section > h1 { |
覆盖成功(并且此时带section
的是先写的,也就是不存在覆盖的推断,实打实的权重高)
或者可以写一个权重为1|0|0|1|1
的,比如
1 | .section > h1 { |
也可以成功覆盖