Skip to content

一个dom元素的样式来源可以有很多, 比如开发者定义的、浏览器默认的, 或者有多个选择器选中了同一个元素; 当多个来源中的属性有重合时, 究竟应用哪个来源中的属性, 这是css的核心问题。

层叠是css的核心, 从层叠样式表这个名字上就能看出来, 它是一个定义了如何合并来自多个源的属性值的算法。

重要性(Importance)

重要性是凌驾于所有其他层叠规则之上的方法, 通过在属性值后加!important, 将这条css属性声明 设置为important的。

  • important的属性一定覆盖normal属性
  • 当都声明为!important或者都没有声明为!important时, 往下走吧

源(Origin)

一般的, css的源被分为三类:

类别描述
用户代理/浏览器样式表(User-agent stylesheets)浏览器样式表是是浏览器提供的默认样式。每个浏览器都有一套自己的默认样式,用于在未明确指定样式时显示HTML元素。例如,大多数浏览器会默认将<h1>元素显示为大号加粗字体,<a>元素显示为蓝色并在鼠标悬停时下划线等。这些默认样式的目的是为了在没有CSS的情况下提供一个基本的、可读的文档结构。
作者/开发者样式表(Author stylesheets)web开发者为文档设置的样式, 定义了网页的外观。
用户样式表(User stylesheets)Web 浏览器允许用户编写 CSS 样式表,浏览器使用这些样式表来覆盖页面设计者所做的样式选择。但目前几乎被淘汰,如chrome不再支持。究其原因, 现代的网页早以不像是古早时候只是一个结构简单文档, 而是变成了应用程序。开发者样式越来越复杂越来越完善, 定义用户样式大概率不会让网页更好, 反而是破坏了网页的正常效果、设计主题。 所谓用户样式, 到现在, 只在markdown这样的简单排版文档里还有存活空间。

层叠的顺序如下图:

Order (low to high)OriginImportance
1user-agent (browser)normal
2usernormal
3author (developer)normal
4CSS @keyframe animations
5author (developer)!important
6user!important
7user-agent (browser)!important
8CSS transitions

可以看到, 当开发者样式与浏览器样式冲突时, 开发者样式的优先级更高; 但当应用了!important时, 结果将相反, 应用了!important的开发者样式无法覆盖应用了!improtant的浏览器样式。

当源相同时, 那么继续往下走

优先级(Specificity)

当css属性具有相同的源(origin)时, 我们会开始为css属性计算得到一个优先级, 优先级高的会覆盖掉优先级低的。

行内样式

一般来说所有css在一个样式表环境里; 但在web开发者的角色里, 还可以为dom元素设置行内样式。

行内样式总会覆盖外部样式表的任何样式,因此可看作是具有最高的优先级。

优先级计算

优先级的计算原则是: 选择器越具体, 优先级越高。

比如

html
#text {...}
p {...}
<p id="text"></p>

这里的两个选择器都能选择这个p元素, 但一个是标签选择器, 泛泛地选中了文档中所有的p标签; 而#text选中具有id=text的元素, 要比标签选择具体的非常多。 在这种情况下, id选择器的优先级比标签选择器要高。


选择器的优先级被量化为一个长度为3的元组: (x, y, z), 进行字典序比较。

这里的字典序比较可能造成误解。

这里的字典序比较指的是, 索引小的权重大的比较方式, 只有当前位相同才会比较下一位。

比如[2, 1, 1] > [1, 3, 3], 因为首位2 > 1

比如[2, 2, 1] > [2, 1, 3], 因为首位相同, 所以比较第二位, 2 > 1

优先级元组(x, y, z)中三个位置分别代表的意义是 :

  • x: 选择器中ID选择器的数量
  • y:选择器中 (类选择器、属性选择器、伪类选择器)的数量
  • z: 选择器中(标签选择器、伪元素选择器)的数量

给出以下例子帮助了解

css
#app {...} // (1, 0, 0)
.box {...} // (0, 1, 0)
div {...} // (0, 0, 1)
#app .box {...} // (1, 1, 0)
#app > .list > a {...} // (1, 1, 1)
a:hover {...} // (0, 1, 1)
#app::before {...} // (1, 0, 1)
.item.selected {...} // (0, 2, 0)

继承(inheritance)

参考

CSS 层叠 - CSS:层叠样式表 | MDN (mozilla.org)

层叠、优先级与继承 - 学习 Web 开发 | MDN (mozilla.org)

优先级 - CSS:层叠样式表 | MDN (mozilla.org)

Cascade layers - Learn web development | MDN (mozilla.org)

什么是用户样式表? (thoughtco.com)