前言
前端开发有时候我明明写了 css 属性但是样式却没能在浏览器中生效,这其实很大概率原因就是你可能还不了解 css 属性值的计算过程,本期文章就带大家过一遍这部分知识,或许有你不清楚的内容🤷♂️
css 属性值的计算过程
CSS属性值的计算过程指的是浏览器渲染引擎将 CSS 属性从声明到最终渲染的处理流程,直白点就是 css 属性从没有值 到 有值的 过程。
css 属性并不是不写 css 就没有属性了,浏览器会有个 用户代理样式表 user agent stylesheet
,你可以理解为浏览器默认的样式
比如 我写一个 h1
元素,不给他写任何属性,默认就会有如下样式

这里你会发现 h1 默认样式中有个
display: block;
这其实就是为啥 h1 是一个块级元素,就是因为浏览器赋予了它这个属性,仅此而已,在 html 语义化出来之前你可以这样叫,什么块级元素都是html5
之前的叫法,h5 出来之后官方摒弃了这个说法,如今你要知道的是这都是 css 属性默认值的效果
当我们展开 computed,你就会看到更多的属性,computed 就是这个属性最终计算出来的样式,实际上 computed 中有这个 元素 的所有样式属性
css 属性值的计算过程总览:
- 确定声明值
- 层叠
- 继承
- 使用默认值
第一步:确定声明值
这个会从两个表中获取,一个是作者样式表,一个就是上面提到的 浏览器默认样式表,其英文名为 user agent stylesheet
,这里直译起来是用户代理样式表不方便理解。两个样式表的样式都是声明值
早期其实还有个
user stylesheet
用户样式表,这个样式表在早期的 ie 浏览器存在,在 IE 中,可以转到Tool
>Internet Options
>General Tab
>Accessibility button
>Accessibility Window
>User style sheet section
>"使用我的样式表格式化文档"复选框。其实就是用户在浏览器夹杂一些自己写的样式:参考stackoverflow css - 默认、用户和作者样式表有什么区别?_Stack Overflow中文网
作者样式表 就是我们写的 css 属性,若我们引入了 ui 库,这些 ui 组件的 样式也是 作者样式表
确定声明值 也有步骤:
- 找到 没有冲突 的样式,直接作为计算后的样式
- 将相对单位转成绝对单位
比如我给 h1 加一个 color 属性,color 在浏览器默认样式表中不存在,因此没有冲突,color 就会作为计算后的样式
浏览器默认样式表中的 h1 有一个 font-size: 2em;
em
就是相对单位,它相对的是父容器的 字体大小,我这儿没有给父容器,因此相对的是浏览器的默认字体大小 16px
,因此这里 h1 最终 computed 就是 32px 的 font-size。所以说假设我们给 h1 一个 父容器并且设置 font-size 15px,那么最终 h1 的font-size 就是 30px
相对单位不仅仅说的是 em,%,rem 这种,还包括了 font-weight: bold,color: red 等这种关键字,bold 就是对应 字重 700, red 就是对应 rgb(255, 0, 0)
第二步:层叠
层叠的目的就是一件事:解决冲突,这个过程才是最重要的
层叠有三个步骤:
- 比较重要性
- 比较特异性
- 比较源次序
先看重要性,重要性从高到低:
- 带有 important 的作者样式表
- 带有 important 的默认样式表
- 作者样式表
- 默认样式表
由于早期的 user stylesheet 已经不存在了,这里不做探讨
作者样式表 会覆盖 默认样式表 这很好说明
这里我在代码中写了 h1 标签的样式,默认样式表中的 font-size 就被覆盖了
这里我想要验证 带有 important 的默认样式表 会大于 作者样式表,但是始终没能成功,input 有个 属性 writing-mode,默认样式就有个 important 值,但是我写了不带 important 的 input 的 writing-mode 也能覆盖,这里有大佬清楚可以评论区补充下🚀。
第二步:比较特异性
特异性英文单词就是 specificity
,一般我们会说成权重
内联样式 | ID选择器 | 类选择器、属性选择器、伪类 | 元素选择器、伪元素 | 通配符、关系选择器 |
---|---|---|---|---|
权重:1000 | 权重:100 | 权重:10 | 权重:1 | 权重:0 |
style="color: red" |
#header |
.container [type="text"] :hover |
div ::before |
* > + |
vscode 上 hover 样式选择器时会呈现最终的权重,不过由于不是写的内联样式,他只会给你呈现 后面三个值。

另外,mdn 上关于 css 权重有个 很形象的 图,这里可以看到 important 的权重是 10000

因此直观上感受,选择器内容越多,权重就会比较高
特殊伪类的权重计算
特殊伪类这里说的是 :is() 、:not() 、:where()
:is() 和 :not() 二者均是采用 参数中 最高特异性选择器的权重

如图这个例子,选取 item 中 值最高的 #id 作为最终权重,not 同理
:where() 权重始终为 0,无论参数中选择器的权重如何

where 的功能与 is 几乎相同,允许指定多个选择器,但是 where 权重始终为 0,这就是为了方便后续覆盖
为何要少用 !important
!important
权重是 10000,我们用它一时爽,后面维护起来就要骂娘了,主要是因为用 !important 会带来一些问题:
-
破坏 css 级联原则
css 全称 就是 Cascading Style Sheets 层叠样式表,层叠一词就能直接体现 选择器 优先级的重要性,当我们对某个样式使用了 !important 时,它就会绕过这个机制,这样样式覆盖我们就无法预测
-
难以调试
当多个 !important 冲突时,这个时候最终生效的样式只能是最后加载的样式,而非选择器权重,这样调试起来效率就很低
第三步:比较源次序
若前面的重要性一样,特殊性一样,那么最终就是源次序靠后的胜出
比如我在同一个选择器中对同一个 css 属性写了多次,那么最终只取最后一个值
css
div h1.className {
font-size: 10px;
font-size: 20px;
}
这里最终就是 20px 的 font-size
这个例子过于简单了,这里我再举一个隐形一点的🌰
比如这里我写一个样式
css
.parent {
width: 400px;
height: 400px;
padding: 20px;
border: 5px solid;
background-clip: content-box;
background: red;
}
background-clip
属性设置元素的背景是否延伸到边框、内边距盒子,内容盒子下面,content-box
就不会让背景色延伸到 padding
,实际上这里最终效果全部覆盖了

这其实就是因为 background-clip
被覆盖了,background
属性展开可以看到里面具有 background-clip
属性,且用的是默认值 initial
,在源次序中 initial
取胜

因此这里我们可以将 background-clip
属性放最后写,或者也可以直接写 background: red content-box
第三步:继承
第二步骤结束后,很多属性是没有值的,若这些属性 默认可以继承 ,则使用继承,
比如 font-size 容易继承,但是background-color 默认无法继承,默认无法继承可以用 inherit 作为 value 去手动继承
css
.child {
background: inherit;
}
第四步:使用默认值
若继承过后还有属性没有值,那么就会使用 css 属性的默认值,这就是 user agent stylesheet
,比如 position
的默认值 为static
最后
了解这部分内容应该会对你 开发 css 调试上更容易些,但大概也不会让你写出更漂亮的界面,最终该写成啥样的还是啥样🥲
文章中若出现错误内容还请各位大佬见谅并指正。如果有任何问题或建议,欢迎指出,另外,有不懂之处欢迎在评论区留言。如果觉得文章对你的学习有所帮助,还请 关注、点赞、收藏 一键三连,感谢支持!欢迎关注我的公众号:
Dolphin_Fung