承接 Geoff 关于 CSS 中的第二个“S” 的介绍文章,现在让我们将聚光灯转向 CSS 中的“C” - 我们称之为层叠。这是事情开始变得混乱,甚至有时令人困惑的地方。
您是否曾经编写过一个 CSS 属性,但该值似乎不起作用?也许您不得不使用 !important
来使其生效。或者,您可能求助于在 HTML 文件中的元素上内联编写 CSS。
<div style="background:orange; height:100px; width:100px;">
Ack, inline!
</div>
说到内联样式,您是否想知道为什么 SVG 编辑器使用它们而不是单独的 CSS 文件?这看起来有点奇怪,对吧?
<svg id="icon-logo-star" viewBox="0 0 362.62 388.52" width="100%" height="100%">
<style>
.logo {
fill: #ff9800;
}
</style>
<title>CSS Tricks Logo</title>
<path class="logo" d="M156.58 239l-88.3 64.75c-10.59 7.06-18.84 11.77-29.43 11.77-21.19 0-38.85-18.84-38.85-40 0-17.69 14.13-30.64 27.08-36.52l103.6-44.74-103.6-45.92C13 142.46 0 129.51 0 111.85 0 90.66 18.84 73 40 73c10.6 0 17.66 3.53 28.25 11.77l88.3 64.75-11.74-104.78C141.28 20 157.76 0 181.31 0s40 18.84 36.5 43.56L206 149.52l88.3-64.75C304.93 76.53 313.17 73 323.77 73a39.2 39.2 0 0 1 38.85 38.85c0 18.84-12.95 30.61-27.08 36.5l-103.61 45.91L335.54 239c14.13 5.88 27.08 18.83 27.08 37.67 0 21.19-18.84 38.85-40 38.85-9.42 0-17.66-4.71-28.26-11.77L206 239l11.77 104.78c3.53 24.72-12.95 44.74-36.5 44.74s-40-18.84-36.5-43.56z"></path>
</svg>
好吧,层叠与之关系很大。继续阅读以了解样式方法如何影响应用于元素的内容,以及如何利用层叠的优势,因为相信我,一旦您掌握了它,它将是一件美妙的事情。
TL;DR:直接跳转到 CSS 排序图,以直观了解所有内容的工作原理。
层叠关心样式的编写方式和位置
您可以通过多种方式将 CSS 规则应用于元素。以下是将 stroke: red;
应用于同一元素的示例。这些示例按升序优先级排序,其中最高优先级位于底部
<!-- Inheritance -->
<g style="stroke: red">
<rect x="1" y="1" width="10" height="10" /> <!-- inherits stroke: red -->
</g>
<!-- Inline attributes -->
<rect x="1" y="1" width="10" height="10" stroke="red" />
<!-- External style sheet -->
<link rel="stylesheet" href="/path/to/stylesheet.css">
<!-- Embedded styles -->
<style>
rect { stroke: red; }
</style>
<!-- Different specificity or selectors -->
rect { stroke: red; }
.myClass { stroke: red; }
#myID { stroke: red; }
<!-- Inline style -->
<g style="stroke: red"></g>
<!-- Important keyword -->
<g style="stroke: red !important"></g>
继承?嵌入?外部?内联?特异性?重要?是的,很多术语被抛来抛去。让我们稍微分解一下,因为每一个术语都决定了网页加载时浏览器最终使用什么。
元素可以从其他元素继承样式
HTML 和 SVG 元素都可以继承应用于其他元素的 CSS 规则。我们称之为父子关系,其中应用 CSS 的元素是父元素,包含在父元素内部的元素是子元素。
<div class="parent">
<div class="child">I'm the child because the parent is wrapped around me.</div>
</div>

如果我们设置父元素的文本颜色,并且没有在子元素上声明文本颜色,那么子元素将向上查找父元素以了解其文本的颜色应该是什么。我们称之为继承,它是样式如何层叠到它匹配的元素的典型例子......或者“向上冒泡”到下一个匹配的样式的链中。
但是,继承在样式方法中具有最低优先级。换句话说,如果子元素有一个特定于它的规则,那么继承的值将被忽略,即使继承的值可能有一个重要的关键字。以下是一个例子
<div class="parent" style="color: red !important;">
<div class="child">I'm the child because the parent is wrapped around me.</div>
</div>
查看 CodePen 上 Geoff Graham 的笔 子元素忽略带有 !important 的内联继承 (@geoffgraham)。
SVG 内联属性
对于 SVG 元素,我们还可以使用内联属性应用样式,其中内联属性在层叠中具有第二低优先级。这意味着样式表中的 CSS 规则将能够覆盖它们。
<rect x="1" y="1" width="10" height="10" stroke="red" />
rect {
stroke: blue;
}
查看 CodePen 上 Geoff Graham 的笔 样式表覆盖 SVG 内联属性 (@geoffgraham)。
大多数 SVG 编辑器使用内联属性来实现可移植性;也就是说,能够复制某些元素并粘贴到其他地方而不会丢失属性。然后,用户可以使用生成的 SVG 并使用外部样式表对其元素进行样式化。
样式表
样式表分为两种:外部和嵌入式
<!-- External style sheet -->
<link rel="stylesheet" href="/path/to/stylesheet.css">
<!-- Embedded styles -->
<style>
div { border: 1px solid red }
</style>
嵌入式样式与外部样式表具有相同的优先级。因此,如果您具有相同的 CSS 规则,则适用排序规则。
查看 CodePen 上 Geoff Graham 的笔 嵌入式样式覆盖样式表规则 (@geoffgraham)。
所有样式表都遵循排序规则,其中定义较晚的文件将比定义较早的文件具有更高的优先级。在本例中,stylesheet-2.css
将优先于 stylesheet-1.css
文件,因为它最后定义。
<link rel="stylesheet" href="/path/to/stylesheet-1.css">
<link rel="stylesheet" href="/path/to/stylesheet-2.css">
特异性或选择器
您选择元素的方式也将决定应用哪些规则,其中标签(例如 <p>
、<div>
)、类(例如 .my-class
)和 ID(例如 #myI-id
)具有升序优先级。
查看 CodePen 上 Geoff Graham 的笔 按选择器划分特异性 (@geoffgraham)。
在上面的示例中,如果您有一个同时具有 .my-class
和 #my-id
的 div 元素,那么边框将为红色,因为 ID 比类和标签具有更高的优先级。
*特异性比排序规则具有更高的优先级,因此,无论您的规则位于顶部还是底部。特异性仍然具有更高的优先级,并且将被应用。
排序
CSS 规则始终从左到右,然后从上到下优先级排序。
<!-- Blue will be applied because it is on the right -->
<div style="border: 1px solid red; border: 1px solid blue;"></div>
<style>
div {
border: 1px solid red;
border: 1px solid blue; /* This will be applied because it is at the bottom */
}
</style>
内联样式
内联样式具有第二高的优先级,仅次于 !important
关键字。这意味着内联样式仅会被重要关键字覆盖,而不会被其他任何东西覆盖。在内联样式中,适用正常的排序规则,从左到右,从上到下。
<div style="1px solid red;"></div>
重要关键字
说到 !important
关键字,它用于覆盖排序、特异性和内联规则。换句话说,它拥有难以置信的力量。
覆盖内联规则
<style>
div {
/* This beats inline styling */
border: 1px solid orange !important;
/* These do not */
height: 200px;
width: 200px;
}
</style>
<div style="border: 1px solid red; height: 100px; width: 100px;"></div>
在上面的示例中,如果没有重要关键字,div 将具有红色边框,因为内联样式比嵌入式样式具有更高的优先级。但是,使用重要关键字,div 边框变为橙色,因为重要关键字比内联样式具有更高的优先级。
使用 !important
可以非常有用,但应谨慎使用。Chris 对何时使用它有一些想法。
覆盖特异性规则
如果没有重要关键字,这个 div 边框将为蓝色,因为在特异性中,类比标签具有更高的优先级。
<style>
/* Classes have higher priority than tags */
.my-class {
border: 1px solid blue;
height: 100px;
width: 100px;
}
div {
border: 1px solid red;
height: 200px;
width: 200px;
}
</style>
<div class="my-class"></div>
查看 CodePen 上 Geoff Graham (@geoffgraham) 的 类比标签。
但是!将重要关键字添加到标签规则中,会告诉元素忽略级联并优先于类规则。
<style>
.my-class { border: 1px solid red; }
/* The important keyword overrides specificity priority */
.my-class { border: 1px solid blue !important; }
</style>
<div class="my-class"></div>
查看 CodePen 上 Geoff Graham (@geoffgraham) 的 !important 忽略级联。
覆盖排序规则
好的,我们已经讨论过规则顺序如何影响特异性:底部优于顶部,右侧优于左侧。确保覆盖此规则的方法是再次使用!important
。
在本例中,即使蓝色边框是底部规则,div 也会采用红色边框。感谢!important
的巧妙工作。
<style>
div { border: 1px solid red !important; } /* This wins, despite the ordering */
div { border: 1px solid blue; }
</style>
<div></div>
查看 CodePen 上 Geoff Graham (@geoffgraham) 的 重要性胜过排序。
可视化级联
谁知道 CSS 中的“C”包含了如此多的含义?我们在这里涵盖了很多内容,希望这有助于阐明我们如何编写样式以及样式如何受到影响和应用的方式。级联是一个强大的功能。关于如何正确使用它的观点很多,但您可以看到属性是如何传递和继承到元素的。
更喜欢视觉学习者?这里有一张将所有内容整合在一起的图表。
Thomas,感谢您提供关于 CSS 级联的精美视觉指南。不幸的是,您的文章和图表在技术上并不完全正确:嵌入样式总是覆盖链接样式的说法是错误的。CSS 级联和继承规范没有区分这些,而是将其视为相同的级联来源(作者来源),并且实际上说在计算优先级时,链接样式将被等效的嵌入样式替换(“来自独立链接的样式表的声明由源文档视为在链接顺序中串联的”)。对于来自相同来源且具有相同特异性的样式,只有最终声明顺序才重要。
在您的 Codepen 演示中,实际上有两个嵌入式样式表——一个在
<head>
中,一个在<body>
中(至少,这是我在 DOM 检查器中看到的),后者的获胜仅仅是因为顺序。但是,如果您在最后一个嵌入式样式表之后将链接添加到与外部资源相同的样式中,这些外部样式将覆盖它,就像在您的 Codepen 的这个分叉中一样:https://codepen.io/SelenIT/pen/pQRGEv@Ilya,感谢您指出这个错误。我将相应地修改文章和图表,非常感谢!
我对这种右侧优先于左侧的优先级感到非常困惑。据我所知,您的示例是不完整的:style=”1px solid red” 没有任何作用。您可以更精确一些吗?
或者仅仅是因为它是“在”之前定义的?因此在之前定义的右侧?这不是优先级在右侧,而是编码顺序……
@Ben,感谢提醒,正确的示例应该是
<div style=”border: 1px solid red; border: 1px solid blue;”>
简单来说,如果您有两个应用于相同元素的规则,则由于排序规则,右侧或底部的规则将适用。希望这有帮助。
在阅读这篇文章时,我一直在想在 CSS 中哪些属性是继承的,哪些属性不是。似乎甚至获取所有继承属性的列表也并不容易,而且似乎没有明确/合乎逻辑的规则。我认为对于 CSS 初学者来说,在没有查看 MDN 或其他参考资料的情况下,猜测哪些属性是继承的可能并不容易。
@Guillaume,不幸的是这是正确的,但这听起来是一个制作易于参考的图表的好机会,而且我们喜欢图表:) 让我看看我能做些什么。
嗨,Thomas,我终于找到了列出这些值的方法。长话短说:我通过其搜索表单端点,从 Chromium 网站发送了一个提取请求。您可以在此处找到脚本:https://gist.github.com/cdoublev/1a5c4498adde3c6e775de5f0327dead4。我编辑了我的 Google 表格,它用作个人 CSS 约定来排列 CSS 属性:https://docs.google.com/spreadsheets/d/1JIeXks17Wuad_wtDCoB–GOl1RwBQX7VP1IEd-iDHgo/。我用来对属性进行分组的标签在语义上可能是错误的,但我认为实际上不存在任何命名法。您可以随意将其用于自己的研究(表格可能适合图表)。
注意:已弃用的属性在我表中被自愿忽略。
使用这种方法,一些继承属性缺失了。这就是我最终放弃并手动检查 MDN 上所有属性的原因……似乎几乎所有缺失的属性都是继承的速记属性。但它比尝试使用 MDN 或 W3C 更好。两者都没有提供 API。解析 HTML 来获取每个属性的继承值将是一件很痛苦的事。此外,一些属性在各自的参考列表中缺失:https://mdn.org.cn/en-US/docs/Web/CSS/Reference 和 https://www.w3.org/TR/CSS/#properties。
非常感谢 @Guillaume,这是一项非常了不起的工作。非常感谢您与我们分享。我们将看看如何将这些信息转换为图表,并在最终确定之前与您分享草稿。您介意将您的电子邮件地址发送到 [email protected] 吗?感谢!