CSS 中的特异性是指浏览器如何确定 CSS 样式的重要性、相关性和“优先级”。 在这里,我们将查看所有 CSS 样式类型并使用公司类比来了解如何解决竞争样式。
CSS 选择器概述
有多种方法可以选择您尝试在 CSS 中设置样式的元素。 让我们从查看所有选项开始。
- 类型选择器:使用元素类型选择你想要的元素。 例如,要选择所有
<p>
标记,请在 CSS 样式表中使用p
。 - Pseudo-Elements:顾名思义,伪元素本身并不是元素,而是允许您选择相对于另一个选择器的 HTML 的一部分。 例如,用
p::first-letter
选择每个段落的第一个字母。 - 类选择器:元素上可以设置多个类,以便在您的 CSS 样式表中选择。 例如,可以用
.header
选择<h1 class='header'>
。 多个元素可以应用相同的类。 - 属性选择器:选择应用了特定类型属性的元素。 例如,使用
input[type='number']
选择仅接受数字的输入。 - Pseudo-Classes:根据元素所处的 CSS 状态选择元素。 例如,使用
button:hover
设置按钮的悬停状态。 查看这些先前关于 :target、:hover 和 :active 伪类的教程以了解更多信息。 - ID 选择器:选择具有唯一 ID 的特定元素。 每个 ID 只能有一个元素,而类可以应用于多个元素。 例如,选择
<h1 id='mainHeader'>
和#mainHeader
。 - 内联样式:内联样式直接应用于具有
style
属性的元素,因此您实际上不使用任何 CSS 选择器。 例如,您可以直接使用<h1 style='color: blue;'>
将标题字体颜色设为蓝色
CSS 选择器及其“权重”
上面列出的每种类型的选择器都有一个权重。 所有这些可以分为四个主要组:
- 最低权重:类型和伪元素选择器
- 低权重:类、属性和伪类选择器
- 中等重量:ID选择器
- 高权重:内联样式
如果将不同权重的样式应用于同一元素,则将应用具有较高权重的样式。 如果应用了偶数权重的样式,则将应用最后出现的样式(最靠近样式表的末尾)。 这是由于 CSS(层叠样式表)的“层叠”效果。
对于任何正在设置样式的元素,具有最高权重的最后一个适用的样式块将应用于您的元素。 不过,内联样式将胜过 CSS 选择器样式。 💅
当两个相同权重的选择器应用于一个元素时,它计为权重的 2 倍。 因此,例如,使用两个类选择的元素将比 CSS 中的一个具有更高的权重。
.gator.cayman { // two classes color: purple; } .gator { // one class color: purple; }
我们大多数 Web 开发人员在某些时候将面临的主要问题是多种样式相互干扰。 如果您使用 CSS 框架,例如 Material UI,您可能会尝试覆盖一些默认样式。 或者,您可能有一个旧的(且杂乱无章的🙈)styles.css
文件,您必须在其中不断提高特异性,因为不清楚为什么您的样式没有按预期应用。
就像 Web 开发中的任何事情一样,很好地理解您的工具将导致它们被更准确地使用。 让我们看看选择器的不同组合如何影响特异性以及一些技巧来让您的样式按预期应用。 🤓
竞争选择器的问题
了解不同的选择器具有不同的权重对于组织 CSS 至关重要。 但是,如果不清楚什么具有更高的权重怎么办?
假设我们有一个包含两个完整 CSS 块的段落:一个具有三个匹配类,另一个块具有一个类型属性和两个匹配类。
例如,让我们使用三个类和应用到它的 number
类型属性来获取这个输入。
<input type='number' class='gator cayman reptile'>
如果我们应用这些竞争选择器(三个匹配类 vs. 两个匹配的类和一个属性),哪一个会被应用?
.gator.cayman.reptile { color: purple; } [type='number'].gator.cayman { color: green; }
在这种情况下,两个块的“重量”完全相等。 属性选择器和类选择器具有相同的权重,每个块共有三个。 由于它们是偶数,我们依赖 CSS 的级联效果。 最后一个被应用,输入字体颜色将为绿色。🐊
但是,当您混合不同权重的选择器时,这会变得有点复杂。
让我们更新我们的输入以具有一个 ID,它比类和属性具有更高的权重。
<input type='number' id='gatorInput' class='gator cayman reptile'>
如果我们再次有相互竞争的风格,并为一种风格使用 ID,另一种则使用类/属性,哪一个会被应用?
#gatorInput { color: purple; } [type='number'].gator.cayman.reptile { color: green; }
在第一个块中,仅使用一个 ID 来应用样式。 在第二个块中,有三个类和一个属性选择器,它位于最后。 即使第二个块中有更多的选择器,ID 选择器的权重更高,文本会变成紫色! 💥
具有较高权重的选择器总是胜过具有较小权重的选择器,即使有多个较低权重的选择器。 🏋
选择权重技巧
当您只需要更多的权重时,CSS 中的一个技巧(好吧,hack 💩)是在同一个 CSS 块中重复一个类。
input.gator.gator { color: purple; } input.gator { color: green; }
您可能会惊讶地发现,第一个块的权重是两个类,而第二个块的权重是一个类,尽管第一个块只是重复了类 .gator
。 因为两个类的权重比一个类高,所以输入的文本会是紫色的! 🚀
您永远不需要在生产级代码中使用此技巧,因为它表明您具有非常相似的权重样式竞争。 理想情况下,您应该更清楚地定义这些样式。 但是,当您处于“让它工作”模式时,这是您的 CSS 工具箱中的一个不错的工具。 ✨
CSS 特异性的公司类比
特定性有时会让人感觉违反直觉,尤其是当您陷入向 CSS 添加越来越多选择器的恶性循环中时。 我发现有助于考虑特殊性的一种方法是考虑具有明确资历水平的公司。
以下是我们公司按资历(从低到高)排列的角色:
- 雇员
- 经理
- 董事
- 副总裁
- 一位 CEO(我们稍后再谈 CEO)
现在让我们将这些角色映射到我们的选择器:
- employees:类型和伪元素选择器
- managers:类、属性和伪类选择器
- directors:ID 选择器
- VPs:内联样式
让我们看一个新的例子。 在这种情况下,我们有一个包含两个类和一个 ID 的段落。
<p id='gatorParagraph' class='gator reptile'> blah blah blah </p>
#gatorParagraph { color: purple; } p.gator.reptile { color: green; }
我们有一个仅使用 ID 的块和另一个使用元素类型 (<p>
) 和两个类的块。 乍一看,可能很难知道哪个会被应用。
如果我们用我们的公司类比,我们有一位董事说要把文本变成紫色。 另一方面,我们有一名员工和两名经理说要绿色环保。 因为董事的资历最高,她可以胜过员工和经理的意见。 所以文字必须是紫色的!
(没有评论这是否是公司应该做出决定的方式😉)。
将每个权重级别视为升级应用哪种样式的决定的一种方式。 如果不能由同级的选择器决定,则升级它会将决定权交给更高级别的选择器。
作为一般规则,最好编写足够具体的 CSS,这样您就不必想方设法不断升级它。 请注意,一旦您引入了新级别的资历,例如 ID,您也可能会无意中覆盖其他样式。
!重要的是CEO
到目前为止,我们还没有讨论过我们公司的 CEO 在这个 CSS 特异性的类比中是谁。 什么比内联样式更高? !important
规则!
使用与之前相同的示例,让我们将 !important
添加到先前具有较低权重/优先级的块中。
#gatorParagraph { color: purple; } p.gator.reptile { color: green !important; }
添加 !important
将始终将资历升级为可能的最高级别。 以我们公司的类比,我们现在有一个董事与一个董事。 一名员工、两名经理和首席执行官。 一旦介绍了 CEO,她就可以胜过任何其他建议。 💣
请不要使用!重要
!important
规则是一个滑坡,在你的 CSS 样式中看到它通常是一个危险信号,需要重新组织特异性。 很少有元素只能通过取消其余的 CSS 规则来设置样式,否则这些规则将被应用。
一旦引入 !important
,它通常会导致被过度使用,如下例所示。 !important
相互抵消,你又不得不理解每个块的重量和级联效应。
#gatorParagraph { color: purple !important; } p.gator.reptile { color: green !important; }
不要使用 !important
规则,而是尝试在浏览器中打开您的开发工具,以更好地了解哪些样式会干扰您的新样式。
一旦您知道哪些样式给您带来麻烦,您可以添加其他相同权重级别的选择器,或者更新您的标记以使用不同的选择器。 🌈
使用 !important 通常会不可避免地导致使用 !important 的 CSS 样式相互竞争。 🙈
通用选择器和组合器
通用选择器 (*
) 和组合器不会影响选择器的重量。 组合器包括子选择器(>
)、通用兄弟选择器(~
)和相邻兄弟选择器(+
)。
例如,如果我们有一个有两个跨度的段落,使用子组合器不会比不使用它增加特异性:
<p id='gatorParagraph'> <span class='reptile'>eggs</span> <span class='reptile'>nest</span> </p>
#gatorParagraph > .reptile { color: purple; } #gatorParagraph .reptile{ color: green; }
这些 CSS 块具有相同的特性——子组合器没有区别——所以文本将是绿色的。
有用的网址
Estelle Weyl 将理解 CSS 特异性的最佳视觉效果之一称为 specifishity。 看看这个! 🤓
此外,如果您不热衷于自己添加特异性权重,那么有一个 特异性计算器 可以为您计算。 🥳