层叠层

本课程旨在向您介绍级联层,这是一种更高级的功能,它建立在 CSS 级联CSS 特异性的基本概念之上。

如果您是 CSS 新手,立即学习本课程可能不那么相关,而且比课程的其他部分更具学术性。然而,了解级联层的基本知识有助于您在项目中遇到它们。您使用 CSS 的次数越多,了解级联层并知道如何利用其强大功能将为您节省大量管理来自不同方、插件和开发团队的 CSS 代码库的痛苦。

当您处理来自多个源的 CSS 时,如果存在相互冲突的 CSS 选择器和相互竞争的特异性,或者当您考虑使用 !important 时,级联层最相关。

预备知识 了解 CSS 的工作原理,包括级联和特异性(学习 CSS 样式基础处理冲突)。
目标 学习级联层的工作原理。

对于应用于元素的每个 CSS 属性,只能有一个值。您可以通过在浏览器的开发工具中检查元素来查看应用于元素的所有属性值。该工具的“样式”面板显示应用于被检查元素的所有属性值,以及匹配的选择器和 CSS 源文件。来自具有优先级的源的选择器将其值应用于匹配的元素。

除了应用的样式外,“样式”面板还会显示划掉的值,这些值与选定的元素匹配,但由于级联、特异性或源顺序而未应用。划掉的样式可能来自具有优先级的同一源,但特异性较低,或者源和特异性匹配,但它们在代码库中较早出现。对于任何应用的属性值,可能会有多个来自许多不同源的声明被划掉。如果您看到一个划掉的样式,其选择器具有更大的特异性,则表示该值缺少源或重要性。

通常,随着网站复杂性的增加,样式表的数量也会增加,这使得样式表的源顺序变得更加重要和复杂。级联层简化了在此类代码库中维护样式表。级联层是显式特异性容器,可对最终应用的 CSS 声明提供更简单、更强大的控制,使 Web 开发人员能够优先处理 CSS 的各个部分,而无需与特异性作斗争。

要理解级联层,您必须很好地理解 CSS 级联。下面的部分简要回顾了重要的级联概念。

级联概念回顾

CSS 中的“C”代表“级联”。它是样式级联在一起的方法。用户代理会执行几个明确定义的步骤来确定每个元素的每个属性的值。我们将在此处简要列出这些步骤,然后深入探讨步骤 4,即级联层,这正是您来此学习的内容

  1. 相关性:查找每个元素的具有选择器匹配的所有声明块。
  2. 重要性:根据规则是正常还是重要进行排序。重要样式是那些设置了 !important 标志的样式。
  3. 来源:在两个重要性桶中的每一个中,按作者、用户或用户代理来源对规则进行排序。
  4. 级联层:在六个来源重要性桶中的每一个中,按级联层进行排序。正常声明的层顺序是从创建的第一个层到最后一个层,然后是未分层的正常样式。此顺序对于重要样式是反向的,未分层的重要样式具有最低优先级。
  5. 特异性:对于具有优先级的源层中的竞争样式,按特异性对声明进行排序。
  6. 作用域邻近度:当具有优先级的源层中的两个选择器具有相同的特异性时,作用域规则中到作用域根的 DOM 层次结构中跳数最少者获胜。有关更多详细信息和示例,请参阅如何解决 @scope 冲突
  7. 出现顺序:当具有优先级的源层中的两个选择器具有相同的特异性和作用域邻近度时,来自最后一个声明的具有最高特异性的选择器的属性值获胜。

对于每个步骤,只有“仍在运行”的声明才会进入下一步“竞争”。如果只有一个声明在运行,它就“赢了”,后续步骤也就无关紧要了。

来源和级联

有三种级联来源类型:用户代理样式表、用户样式表和作者样式表。浏览器按来源和重要性将每个声明分为六个来源桶。有八个优先级级别:六个来源桶、正在过渡的属性和正在动画的属性。优先级顺序从优先级最低的正常用户代理样式,到当前应用的动画中的样式,再到重要的用户代理样式,然后是正在过渡的样式,后者具有最高优先级

  1. 用户代理正常样式
  2. 用户正常样式
  3. 作者正常样式
  4. 正在动画的样式
  5. 作者重要样式
  6. 用户重要样式
  7. 用户代理重要样式
  8. 正在过渡的样式

“用户代理”是浏览器。“用户”是网站访问者。“作者”是您,开发人员。直接在元素上使用 <style> 元素声明的样式是作者样式。不包括动画和过渡样式,用户代理正常样式具有最低优先级;用户代理重要样式具有最高优先级。

来源和特异性

对于每个属性,根据权重(正常或重要)具有优先级的来源中的声明“获胜”。暂时忽略层,将应用优先级最高的来源的值。如果获胜来源对于一个元素有多个属性声明,则比较那些竞争属性值的选择器的特异性。不同来源的选择器之间从不比较特异性。

在下面的示例中,有两个链接。第一个没有应用作者样式,因此只应用用户代理样式(以及您的个人用户样式,如果有的话)。第二个的 text-decorationcolor 由作者样式设置,即使作者样式表中的选择器的特异性为 0-0-0。作者样式“获胜”的原因是,当来自不同来源的样式冲突时,将应用来自具有优先级的来源的规则,而不管没有优先级的来源中的特异性如何。

html
<p><a href="https://example.org">User agent styles</a></p>
<p><a class="author" href="https://example.org">Author styles</a></p>
css
:where(a.author) {
  text-decoration: overline;
  color: red;
}

在撰写本文时,用户代理样式表中的“竞争”选择器是 a:any-link,其特异性权重为 0-1-1。虽然这比作者样式表中的 0-0-0 选择器大,但即使您当前的用户代理中的选择器不同,也无关紧要:作者和用户代理来源的特异性权重从不比较。了解有关如何计算特异性权重的更多信息。

来源优先级总是胜过选择器特异性。如果一个元素属性在多个来源中用正常样式声明进行样式化,作者样式表将始终覆盖在用户或用户代理样式表中声明的冗余正常属性。如果样式很重要,用户代理样式表将始终胜过作者和用户样式。级联来源优先级确保来源之间的特异性冲突永远不会发生。

在继续之前,最后一点:出现顺序只有在优先级来源中的竞争声明具有相同的特异性时才变得相关。

级联层概述

我们现在了解了“级联来源优先级”,但什么是“级联层优先级”?我们将通过解决级联层是什么、它们如何排序以及样式如何分配给级联层来回答这个问题。我们将介绍常规层嵌套层和匿名层。让我们首先讨论级联层是什么以及它们解决了哪些问题。

级联层优先级顺序

与我们根据来源和重要性具有六个优先级级别类似,级联层使我们能够在任何这些来源中创建子来源级别的优先级。

在六个来源桶中的每一个中,可以有多个级联层。层的创建顺序非常重要。正是创建顺序设置了来源内层之间的优先级顺序。

在正常来源桶中,层按每个层的创建顺序排序。优先级顺序是从创建的第一个层到最后一个层,然后是未分层的正常样式。

此顺序对于重要样式是反向的。所有未分层的重要样式级联到一个隐式层中,该层优先于所有非过渡正常样式。未分层的重要样式具有低于任何重要分层样式的优先级。在早期声明的层中的重要样式优先于同一来源中后续声明的层中的重要样式。

对于本教程的其余部分,我们将把讨论限制在作者样式,但请记住层也可以存在于用户和用户代理样式表中。

级联层可以解决的问题

大型代码库可能包含来自多个团队、组件库、框架和第三方的样式。无论包含多少样式表,所有这些样式都以单个来源级联在一起:作者样式表。

将来自许多来源的样式级联在一起,尤其是来自不协同工作的团队的样式,可能会产生问题。不同的团队可能有不同的方法;一个团队的最佳实践可能是降低特异性,而另一个团队的标准可能是在每个选择器中包含一个 id

特异性冲突可能会迅速升级。Web 开发人员可能会通过添加 !important 标志来创建“快速修复”。虽然这可能看起来是一个简单的解决方案,但它通常只是将特异性战争从正常声明转移到重要声明。

就像级联来源在用户、用户代理和作者样式之间提供了一种权力平衡一样,级联层提供了一种结构化的方式来组织和平衡单个来源内的关注点,就好像来源中的每个层都是一个子来源。可以为每个团队、组件和第三方创建一个层,样式的优先级基于层顺序。

层内的规则级联在一起,而不会与层外的样式规则竞争。级联层能够优先处理整个样式表而不是其他样式表,而无需担心这些子来源之间的特异性。

层优先级总是胜过选择器特异性。具有优先级的层中的样式“胜过”优先级较低的层。失败层中选择器的特异性无关紧要。特异性对于层内的竞争属性值仍然很重要,但层之间没有特异性问题,因为只考虑每个属性的最高优先级层。

嵌套级联层可以解决的问题

级联层允许创建嵌套层。每个级联层都可以包含嵌套层。

例如,可以将组件库导入到 components 层中。常规级联层会将组件库添加到作者来源,从而消除与任何其他作者样式的特异性冲突。在 components 层中,开发人员可以选择定义各种主题,每个主题都作为一个单独的嵌套层。这些嵌套主题层的顺序可以根据媒体查询(参见下面的层创建和媒体查询部分)来定义,例如视口大小或方向。这些嵌套层提供了一种创建主题的方式,它们不会基于特异性发生冲突。

嵌套层的功能对于任何从事组件库、框架、第三方小部件和主题开发的人来说都非常有用。

创建嵌套层的功能也消除了对层名称冲突的担忧。我们将在嵌套层部分介绍这一点。

“作者可以创建层来表示元素默认值、第三方库、主题、组件、覆盖和其他样式关注点——并且能够以明确的方式重新排序层的级联,而无需更改每个层内的选择器或特异性,也无需依赖出现顺序来解决层间的冲突。”

级联和继承规范

创建级联层

可以使用以下任一方法创建层

  • @layer 声明 at-rule,使用 @layer 后跟一个或多个层的名称来声明层。这会创建命名层,而无需为其分配任何样式。
  • @layer 块 at-rule,其中块内的所有样式都添加到命名或未命名层中。
  • layer 关键字或 layer() 函数的 @import 规则,它将导入文件的内容分配到该层中。

如果尚未初始化具有该名称的层,则所有三种方法都会创建一个层。如果 @layer at-rule 或带有 layer()@import 中未提供层名称,则会创建一个新的匿名(未命名)层。

注意:层的优先级顺序是它们被创建的顺序。不在层中或“未分层样式”的样式级联到一个最终的隐式标签中。

在讨论嵌套层之前,让我们更详细地介绍创建层这三种方式。

用于命名层的 @layer 声明 at-rule

层的顺序由它们在 CSS 中出现的顺序设置。使用 @layer 后跟一个或多个层的名称而不分配任何样式来声明层是定义层顺序的一种方式。

@layer CSS at-rule 用于声明级联层并在存在多个级联层时定义优先级顺序。以下 at-rule 声明了三个层,按列出的顺序

css
@layer theme, layout, utilities;

您通常希望将此 @layer 声明(当然,层名称对您的站点有意义)作为 CSS 的第一行,以完全控制层排序。

如果以上语句是站点 CSS 的第一行,则层顺序将为 themelayoututilities。如果在此语句之前创建了一些层,只要这些名称的层尚不存在,这三个层将被创建并添加到现有层列表的末尾。但是,如果具有相同名称的层已经存在,则以上语句将只创建两个新层。例如,如果 layout 已经存在,则只创建 themeutilities,但在这种情况下,层的顺序将为 layoutthemeutilities

用于命名层和匿名层的 @layer 块 at-rule

可以使用块 @layer at-rule 创建层。如果 @layer at-rule 后跟一个标识符和一个样式块,则该标识符用于命名该层,并且此 at-rule 中的样式将添加到该层的样式中。如果具有指定名称的层尚不存在,则将创建一个新层。如果具有指定名称的层已经存在,则样式将添加到先前存在的层中。如果在使用 @layer 创建样式块时未指定名称,则 at-rule 中的样式将添加到新的匿名层中。

在下面的示例中,我们使用了四个 @layer 块 at-rule 和一个 @layer 声明 at-rule。此 CSS 按列出的顺序执行以下操作

  1. 创建一个名为 layout 的层
  2. 创建一个未命名、匿名层
  3. 声明一个包含三个层的列表,并且只创建两个新层,themeutilities,因为 layout 已经存在
  4. 向已有的 layout 层添加额外的样式
  5. 创建第二个未命名、匿名层
css
/* file: layers1.css */

/* unlayered styles */
body {
  color: #333333;
}

/* creates the first layer: `layout` */
@layer layout {
  main {
    display: grid;
  }
}

/* creates the second layer: an unnamed, anonymous layer */
@layer {
  body {
    margin: 0;
  }
}

/* creates the third and fourth layers: `theme` and `utilities` */
@layer theme, layout, utilities;

/* adds styles to the already existing `layout` layer */
@layer layout {
  main {
    color: black;
  }
}

/* creates the fifth layer: an unnamed, anonymous layer */
@layer {
  body {
    margin: 1vw;
  }
}

在上述 CSS 中,我们按顺序创建了五个层:layout<anonymous(01)>themeutilities<anonymous(02)>,以及一个包含在 body 样式块中的第六个隐式未分层样式层。层的顺序是层创建的顺序,未分层样式的隐式层始终在最后。一旦创建,就无法更改层顺序。

我们将一些样式分配给名为 layout 的层。如果命名层尚不存在,则在 @layer at-rule 中指定名称,无论是否将样式分配给该层,都会创建该层;这会将该层添加到现有层名称系列的末尾。如果命名层已经存在,则命名块内的所有样式都将附加到先前存在的层中的样式——通过重用现有层名称在块中指定样式不会创建新层。

匿名层是通过在不命名层的情况下将样式分配给层来创建的。样式只能在其创建时添加到未命名层中。

注意:后续使用不带层名称的 @layer 会创建额外的未命名层;它不会将样式附加到先前存在的未命名层。

@layer at-rule 创建一个层(无论是否命名),或者如果命名层已经存在,则将样式附加到该层。我们将第一个匿名层称为 <anonymous(01)>,第二个称为 <anonymous(02)>,这只是为了方便解释。这些实际上是未命名的层。无法引用它们或向它们添加额外的样式。

所有在层之外声明的样式都组合在一个隐式层中。在上面的示例代码中,第一个声明将 color: #333333 属性设置在 body 上。这在任何层之外声明。即使未分层样式具有较低的特异性并且在出现顺序中排在第一位,正常的未分层声明也优先于正常的已分层声明。这解释了为什么即使未分层 CSS 在代码块中首先声明,包含这些未分层样式的隐式层也优先,就好像它是最后一个声明的层一样。

@layer theme, layout, utilities; 这一行中,声明了一系列层,只创建了 themeutilities 层;layout 已在第一行中创建。请注意,此声明不会更改已创建层的顺序。目前无法在声明后重新排序层。

在以下示例中,我们将样式分配给两个层,并在过程中创建并命名它们。由于它们已经存在,在第一次使用时创建,因此在最后一行声明它们没有任何作用。

html
<h1>Is this heading underlined?</h1>
css
@layer page {
  h1 {
    text-decoration: overline;
    color: red;
  }
}

@layer site {
  h1 {
    text-decoration: underline;
    color: green;
  }
}

/* this does nothing */
@layer site, page;

尝试将最后一行 @layer site, page; 移动到第一行。会发生什么?

层创建和媒体查询

如果您使用媒体功能查询定义层,并且媒体不匹配或功能不受支持,则不会创建该层。下面的示例展示了更改设备或浏览器的大小可能会如何更改层顺序。在此示例中,我们只在较宽的浏览器中创建 site 层。然后,我们按顺序将样式分配给 pagesite 层。

html
<h1>Is this heading underlined?</h1>
css
@media (width >= 50em) {
  @layer site;
}

@layer page {
  h1 {
    text-decoration: overline;
    color: red;
  }
}

@layer site {
  h1 {
    text-decoration: underline;
    color: green;
  }
}

在宽屏上,site 层在第一行声明,这意味着 site 的优先级低于 page。否则,site 优先于 page,因为它在窄屏上稍后声明。如果不起作用,请尝试将媒体查询中的 50em 更改为 10em100em

使用 @import 将样式表导入命名层和匿名层

@import 规则允许用户将样式规则从其他样式表直接导入到 CSS 文件或 <style> 元素中。

导入样式表时,@import 语句必须定义在样式表或 <style> 块中的任何 CSS 样式之前。@import 语句必须排在第一位,在任何样式之前,但可以紧跟在创建了一个或多个层但没有为这些层分配任何样式的 @layer at-rule 之后。(@import 也可以紧跟在 @charset 规则之后。)

您可以将样式表导入到命名层、嵌套命名层或匿名层中。以下层分别将样式表导入到 components 层、components 层内的嵌套 dialog 层以及未命名层中

css
@import "components-lib.css" layer(components);
@import "dialog.css" layer(components.dialog);
@import "marketing.css" layer();

您可以将多个 CSS 文件导入到单个层中。以下声明将两个单独的文件导入到单个 social 层中

css
@import "comments.css" layer(social);
@import "sm-icons.css" layer(social);

您可以使用媒体查询功能查询根据特定条件导入样式和创建层。以下代码仅在浏览器支持 display: ruby 并且导入的文件取决于屏幕宽度时,才将样式表导入到 international 层。

css
@import "ruby-narrow.css" layer(international) supports(display: ruby)
  (width < 32rem);
@import "ruby-wide.css" layer(international) supports(display: ruby)
  (width >= 32rem);

注意:没有等效的 <link> 方法来链接样式表。当您无法在样式表中使用 @layer 时,请使用 @import 将样式表导入到层中。

嵌套级联层概述

嵌套层是命名层或匿名层内的层。每个级联层,即使是匿名层,也可以包含嵌套层。导入到另一个层中的层成为该层中的嵌套层。

嵌套层的优势

嵌套层的功能使团队能够创建级联层,而无需担心其他团队是否会将其导入到层中。同样,嵌套使您能够将第三方样式表导入到层中,而无需担心该样式表本身是否具有层。由于层可以嵌套,因此您不必担心外部和内部样式表之间存在冲突的层名称。

创建嵌套级联层

嵌套层可以使用与常规层相同的方法创建。例如,可以使用 @layer at-rule 后跟一个或多个层名来创建,并使用点表示法。多个点和层名表示多层嵌套。

如果您将块 @layer at-rule 嵌套在另一个块 @layer at-rule 中,无论是否带名称,嵌套的块都将成为一个嵌套层。同样,当使用包含 layer 关键字或 layer() 函数的 @import 声明导入样式表时,样式将被分配给该命名或匿名层。如果 @import 语句包含层,则这些层将成为该匿名或命名层内的嵌套层。

我们来看看下面的例子

css
@import "components-lib.css" layer(components);
@import "narrow-theme.css" layer(components.narrow);

在第一行中,我们将 components-lib.css 导入到 components 层。如果该文件包含任何层,无论是命名层还是未命名层,这些层都将成为 components 层中的嵌套层。

第二行将 narrow-theme.css 导入到 narrow 层,这是 components 的子层。嵌套的 components.narrow 将作为 components 层中的最后一个层创建,除非 components-lib.css 已经包含一个 narrow 层,在这种情况下,narrow-theme.css 的内容将附加到 components.narrow 嵌套层。可以使用模式 components.<layerName> 将其他嵌套命名层添加到 components 层。如前所述,可以创建未命名层,但随后无法访问它们。

我们来看另一个例子,其中我们使用以下语句将 layers1.css 导入到命名层中

css
@import "layers1.css" layer(example);

这将创建一个名为 example 的单层,其中包含一些声明和五个嵌套层——example.layoutexample.<anonymous(01)>example.themeexample.utilitiesexample.<anonymous(02)>

要向命名嵌套层添加样式,请使用点表示法

css
@layer example.layout {
  main {
    width: 50vw;
  }
}

根据层顺序确定优先级

层的顺序决定了它们的优先级顺序。因此,层的顺序非常重要。就像级联按来源和重要性进行排序一样,级联也按来源层和重要性对每个 CSS 声明进行排序。

常规级联层的优先级顺序

css
@import "A.css" layer(firstLayer);
@import "B.css" layer(secondLayer);
@import "C.css";

上面的代码创建了两个命名层(C.css 样式附加到未分层样式的隐式层)。让我们假设这三个文件(A.cssB.cssC.css)内部不包含任何其他层。以下列表显示了这些文件内部和外部声明的样式将从最低(1)优先级到最高(10)优先级进行排序。

  1. firstLayer 正常样式(A.css
  2. secondLayer 正常样式(B.css
  3. 未分层正常样式(C.css
  4. 行内正常样式
  5. 动画样式
  6. 未分层重要样式(C.css
  7. secondLayer 重要样式(B.css
  8. firstLayer 重要样式(A.css
  9. 行内重要样式
  10. 过渡样式

层内声明的普通样式优先级最低,并按层创建的顺序排序。第一个创建的层中的普通样式优先级最低,最后一个创建的层中的普通样式在这些层中优先级最高。换句话说,如果存在任何冲突,firstLayer 中声明的普通样式将被列表中任何后续样式覆盖。

接下来是任何在层外声明的样式。C.css 中的样式未导入到层中,并将覆盖来自 firstLayersecondLayer 的任何冲突样式。未在层中声明的样式始终比在层中声明的样式具有更高的优先级(重要样式除外)。

内联样式使用 style 属性声明。以这种方式声明的正常样式将优先于在未分层和分层样式表(firstLayer – A.csssecondLayer – B.cssC.css)中找到的正常样式。

动画样式具有比所有正常样式(包括内联正常样式)更高的优先级。

重要样式,即包含 !important 标志的属性值,优先于我们列表中先前提到的任何样式。它们按正常样式的相反顺序排序。在层外声明的任何重要样式比在层内声明的样式优先级低。层内找到的重要样式也按层创建的顺序排序。对于重要样式,最后创建的层具有最低优先级,而第一个创建的层在声明的层中具有最高优先级。

行内重要样式再次具有比在其他地方声明的重要样式更高的优先级。

过渡样式具有最高优先级。当正常属性值正在过渡时,它优先于所有其他属性值声明,甚至行内重要样式;但仅在过渡期间。

html
<div>
  <h1 style="color: yellow; background-color: maroon !important;">
    Inline styles
  </h1>
</div>
css
@layer A, B;

h1 {
  font-family: sans-serif;
  margin: 1em;
  padding: 0.2em;
  color: orange;
  background-color: green;
  text-decoration: overline pink !important;
  box-shadow: 5px 5px lightgreen !important;
}

@layer A {
  h1 {
    color: grey;
    background-color: black !important;
    text-decoration: line-through grey;
    box-shadow: -5px -5px lightblue !important;
    font-style: normal;
    font-weight: normal !important;
  }
}

@layer B {
  h1 {
    color: aqua;
    background: yellow !important;
    text-decoration: underline aqua;
    box-shadow: -5px 5px magenta !important;
    font-style: italic;
    font-weight: bold !important;
  }
}

在此示例中,最初使用不带任何样式的 @layer 语句 at-rule 定义了两个层(AB)。层样式在两个 @layer 块 at-rule 中定义,这些 at-rule 出现在任何层之外声明的 h1 CSS 规则之后。

使用 style 属性在 h1 元素上添加的行内样式设置了正常的 color 和重要的 background-color。正常的行内样式会覆盖所有分层和未分层的正常样式。重要的行内样式会覆盖所有分层和未分层的正常和重要的作者样式。作者样式无法覆盖重要的行内样式。

正常的 text-decoration 和重要的 box-shadow 不属于 style 行内样式,因此可以被覆盖。对于正常的非行内样式,未分层样式具有优先级。对于重要样式,层顺序也很重要。虽然正常的未分层样式会覆盖层中设置的所有正常样式,但对于重要样式,优先级顺序是相反的;未分层的重要样式比分层样式具有更低的优先级。

仅在层内声明的两种样式是 font-style(正常重要性)和 font-weight(带有 !important 标志)。对于正常样式,最后声明的 B 层会覆盖早期声明的 A 层中的样式。对于正常样式,后面的层优先于前面的层。优先级顺序对于重要样式是反向的。对于重要的 font-weight 声明,首先声明的 A 层优先于最后声明的 B 层。

您可以通过将第一行从 @layer A, B; 更改为 @layer B, A; 来反转层顺序。试一试。哪些样式会因此改变,哪些保持不变?为什么?

层的顺序由它们在 CSS 中出现的顺序设置。在我们的第一行中,我们使用 @layer 后跟层名称声明了层,但没有分配任何样式,以分号结尾。如果省略了这一行,结果也会相同。为什么?我们按 A 然后 B 的顺序在命名的 @layer 块中分配了样式规则。这两个层是在第一行中创建的。如果它们没有被创建,这些规则块也会以该顺序创建它们。

我们包含第一行有两个原因:首先,您可以轻松编辑该行并切换顺序;其次,通常您会发现预先声明层顺序是层顺序管理的最佳实践。

总结

  • 层的优先级顺序是层被创建的顺序。
  • 一旦创建,就无法更改层顺序。
  • 正常样式的层优先级是层创建的顺序。
  • 未分层正常样式优先于正常分层样式。
  • 重要样式的层优先级是相反的,早期创建的层具有优先级。
  • 所有分层的重要样式都优先于未分层的重要(和正常)样式。
  • 正常内联样式优先于所有正常样式,无论是否分层。
  • 重要内联样式优先于所有其他样式,正在过渡的样式除外。
  • 作者样式无法覆盖重要的行内样式(除了临时过渡它们)。

嵌套级联层的优先级顺序

嵌套层的级联优先级顺序与常规层相似,但包含在层内。优先级顺序基于嵌套层创建的顺序。层中的非嵌套样式优先于嵌套的正常样式,而重要样式的优先级顺序则相反。嵌套层之间的特异性权重无关紧要,但对于嵌套层内的冲突样式则很重要。

以下代码创建并向 components 层、components.narrow 嵌套层和 components.wide 嵌套层添加样式

css
div {
  background-color: wheat;
  color: pink !important;
}

@layer components {
  div {
    background-color: yellow;
    border: 1rem dashed red;
    color: orange !important;
  }
}

@layer components.narrow {
  div {
    background-color: skyblue;
    border: 1rem dashed blue;
    color: purple !important;
    border-radius: 50%;
  }
}

@layer components.wide {
  div {
    background-color: limegreen;
    border: 1rem dashed green;
    color: seagreen !important;
    border-radius: 20%;
  }
}

以下是所使用的属性以及每个声明应用原因的摘要

  • background-color:因为未分层正常样式优先于分层正常样式,所以 wheat 颜色胜出。
  • border:因为在一个层内,非嵌套样式优先于正常嵌套样式,所以 red 颜色胜出。
  • color:对于重要样式,分层样式优先于未分层样式,其中在早期声明的层中的重要样式优先于在后期声明的层。在此示例中,嵌套层创建的顺序是 components.narrow,然后是 components.wide,因此 components.narrow 中的重要样式优先于 components.wide 中的重要样式,这意味着 purple 颜色胜出。
  • border-radius:属性仅在嵌套层中设置,因此按声明顺序 20% 半径胜出。

总结

如果您理解了本文的大部分内容,那么恭喜您——您现在已熟悉 CSS 级联层的基本机制。