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