级联层

本课程旨在向你介绍 级联层,这是一项基于 CSS 级联CSS 特异性 基本概念构建的更高级功能。

¥This lesson aims to introduce you to cascade layers, a more advanced feature that builds on the fundamental concepts of the CSS cascade and CSS specificity.

如果你是 CSS 新手,那么学习本课程可能看起来不太相关,并且比本课程的其他部分更具学术性。但是,如果你在项目中遇到级联层,那么了解级联层的基础知识会很有帮助。你使用 CSS 的次数越多,了解级联层并了解如何利用它们的功能,将使你免于管理来自不同各方、插件和开发团队的 CSS 代码库的许多痛苦。

¥If you are new to CSS, working through this lesson may seem less relevant immediately and a little more academic than some other parts of the course. However, knowing the basics of what cascade layers are should you encounter them in your projects is helpful. The more you work with CSS, understanding cascade layers and knowing how to leverage their power will save you from a lot of pain managing a code base with CSS from different parties, plugins, and development teams.

当你使用多个来源的 CSS、存在冲突的 CSS 选择器和竞争的特性时,或者当你考虑使用 !important 时,级联层最为相关。

¥Cascade layers are most relevant when you're working with CSS from multiple sources when there are conflicting CSS selectors and competing specificities, or when you're considering using !important.

先决条件: CSS 工作原理的想法,包括级联和特异性(研究 CSS 第一步级联、特异性和继承)。
目标: 了解级联层的工作原理。

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

¥For each CSS property applied to an element, there can only be one value. You can view all the property values applied to an element by inspecting the element in your browser's developer tools. The tool's "Styles" panel shows all the property values applied to the element being inspected, along with the matched selector and the CSS source file. The selector from the origin with precedence has its values applied to the matching element.

除了应用的样式之外,“样式”面板还显示与所选元素匹配但由于级联、特异性或源顺序而未应用的划掉的值。划掉的样式可能来自具有优先级但较低特异性的相同来源,或者具有匹配的来源和特异性,但在代码库中较早发现。对于任何应用的属性值,可能有来自许多不同来源的多个声明。如果你看到划掉的样式具有更高特异性的选择器,则意味着该值缺乏来源或重要性。

¥In addition to the applied styles, the Styles panel displays crossed-out values that matched the selected element but were not applied due to the cascade, specificity, or source order. Crossed-out styles may come from the same origin with precedence but with lower specificity, or with matching origin and specificity, but were found earlier in the code base. For any applied property value, there may be several declarations crossed out from many different sources. If you see a style crossed out that has a selector with greater specificity it means the value is lacking in origin or importance.

通常,随着站点复杂性的增加,样式表的数量也会增加,这使得样式表的源顺序变得更加重要和复杂。级联层简化了跨此类代码库的样式表维护。级联层是显式特异性容器,可对最终应用的 CSS 声明提供更简单、更好的控制,使 Web 开发者能够确定 CSS 各部分的优先级,而无需考虑特异性。

¥Often, as the complexity of a site increases, the number of stylesheets increases, which makes the source order of the stylesheets both more important and more complex. Cascade layers simplify maintaining stylesheets across such code bases. Cascade layers are explicit specificity containers providing simpler and greater control over the CSS declarations that ultimately get applied, enabling web developers to prioritize sections of CSS without having to fight specificity.

要理解级联层,你必须很好地理解 CSS 级联。以下部分快速回顾了重要的级联概念。

¥To understand cascade layers, you must understand the CSS cascade well. The sections below provide a quick recap of the important cascade concepts.

级联概念回顾

¥Review of the cascade concept

CSS 中的 'C' 代表 "级联"。这是风格层叠在一起的方法。用户代理运行几个明确定义的步骤来确定分配给每个元素的每个属性的值。我们将在这里简要列出这些步骤,然后深入研究步骤 4,级联层,这就是你来这里学习的内容:

¥The 'C' in CSS stands for "Cascading". It is the method by which styles cascade together. The user agent runs through several clearly defined steps to determine the values assigned to every property for every element. We will briefly list these steps here and then dig deeper into step 4, Cascade layers, which is what you came here to learn:

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

对于每个步骤,只有声明 "仍在运行中" 会在下一步中移动到 "compete"。如果只有一个声明正在运行,则为 "wins",并且后续步骤没有意义。

¥For each step, only the declarations "still in the running" move on to "compete" in the next step. If only one declaration is in the running, it "wins", and the subsequent steps are moot.

起源和级联

¥Origin and cascade

有 3 个 级联起源类型:用户代理样式表、用户样式表和作者样式表。浏览器根据来源和重要性将每个声明分类到六个来源存储桶中。有八个优先级:六个原始存储桶、正在转换的属性以及正在动画的属性。优先级顺序是从优先级最低的普通用户代理样式,到当前应用的动画中的样式,再到重要的用户代理样式,然后是优先级最高的正在转换的样式:

¥There are three cascade origin types: user-agent stylesheets, user stylesheets, and author stylesheets. The browser sorts each declaration into six origin buckets by origin and importance. There are eight levels of precedence: the six origin buckets, properties that are transitioning, and properties that are animating. The order of precedence goes from normal user-agent styles, which have the lowest precedence, to styles within currently applied animations, to important user-agent styles, and then styles being transitioned, which have the highest precedence:

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

"user-agent" 是浏览器。"user" 是站点访问者。"author" 就是你,开发者。直接在带有 <style> 元素的元素上声明的样式是作者样式。不包括动画和过渡样式,用户代理普通样式的优先级最低;user-agent 重要样式具有最高的。

¥The "user-agent" is the browser. The "user" is the site visitor. The "author" is you, the developer. Styles declared directly on an element with the <style> element are author styles. Not including animating and transitioning styles, user-agent normal styles have the lowest precedence; user-agent important styles have the highest.

起源和特殊性

¥Origin and specificity

对于每个属性,声明 "wins" 是来自原产地的属性,并根据权重(正常或重要)优先。暂时忽略层,应用来自具有最高优先级的原点的值。如果获胜源对某个元素有多个属性声明,则会比较这些竞争属性值的选择器的 specificity。不同来源的选择器之间永远不会比较特异性。

¥For each property, the declaration that "wins" is the one from the origin with precedence based on the weight (normal or important). Ignoring layers for the moment, the value from the origin with the highest precedence gets applied. If the winning origin has more than one property declaration for an element, the specificity of the selectors for those competing property values are compared. Specificity is never compared between selectors from different origins.

在下面的示例中,有两个链接。第一个没有应用作者样式,因此仅应用用户代理样式(以及你的个人用户样式,如果有)。第二个具有由作者样式设置的 text-decorationcolor,即使作者样式表中的选择器具有 0-0-0 的特殊性。作者样式 "win" 的原因是,当不同来源的样式发生冲突时,将应用具有优先权的来源的规则,而不管不具有优先权的来源的特殊性。

¥In the example below, there are two links. The first has no author styles applied, so only user-agent styles are applied (and your personal user styles, if any). The second has text-decoration and color set by author styles even though the selector in the author stylesheet has a specificity of 0-0-0. The reason why author styles "win" is because when there are conflicting styles from different origins, the rules from the origin with precedence are applied, irrespective of the specificity in the origin that doesn't have precedence.

在撰写本文时,用户代理样式表中的 "competing" 选择器是 a:any-link,其特异性权重为 0-1-1。虽然这比作者样式表中的 0-0-0 选择器大,但即使当前用户代理中的选择器不同,也没关系:来自作者和用户代理来源的特异性权重永远不会被比较。了解有关 如何计算特异性权重 的更多信息。

¥The "competing" selector in the user-agent stylesheet at the time of this writing is a:any-link, which has a specificity weight of 0-1-1. While this is greater than the 0-0-0 selector in the author stylesheet, even if the selector in your current user agent is different, it doesn't matter: the specificity weights from author and user-agent origins are never compared. Learn more about how specificity weight is calculated.

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

¥Origin precedence always wins over selector specificity. If an element property is styled with a normal style declaration in multiple origins, the author style sheet will always override the redundant normal properties declared in a user or user-agent stylesheet. If the style is important, the user-agent stylesheet will always win over author and user styles. Cascade origin precedence ensures specificity conflicts between origins never happen.

在继续之前要注意的最后一件事:仅当优先权来源中的相互竞争的声明具有相同的特殊性时,出现的顺序才有意义。

¥One last thing to note before moving on: the order of appearance becomes relevant only when competing declarations in the origin of precedence have the same specificity.

级联层概述

¥Overview of cascade layers

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

¥We now understand "cascade origin precedence", but what is "cascade layer precedence"? We will answer that question by addressing what cascade layers are, how they are ordered, and how styles are assigned to cascade layers. We'll cover regular layers, nested layers, and anonymous layers. Let's first discuss what cascade layers are and what issues they solve.

级联层优先顺序

¥Cascade layer precedence order

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

¥Similar to how we have six levels of priority based on origin and importance, cascade layers enable us to create sub-origin level of priority within any of those origins.

在六个原始存储桶中的每个存储桶内,可以有多个级联层。图层创建顺序 非常重要。创建顺序决定了原点内各层之间的优先顺序。

¥Within each of the six origin buckets, there can be multiple cascade layers. The order of layer creation matters a lot. It is the order of creation that sets the precedence order among layers within an origin.

在普通的原始存储桶中,图层按照每个图层的创建顺序进行排序。优先顺序是从创建的第一层到最后一层,然后是未分层的普通样式。

¥In normal origin buckets, layers are sorted in the order of each layer's creation. The order of precedence is from the first layer created to the last, followed by unlayered normal styles.

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

¥This order is inverted for important styles. All unlayered important styles cascade together into an implicit layer having precedence over all non-transitioning normal styles. The unlayered important styles have lower precedence than any important layered styles. The important styles in earlier declared layers have precedence over important styles in subsequent declared layers within the same origin.

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

¥For the rest of this tutorial, we will limit our discussion to author styles, but keep in mind that layers can also exist in user and user-agent stylesheets.

级联层可以解决的问题

¥Issues cascade layers can solve

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

¥Large code bases can have styles coming from multiple teams, component libraries, frameworks, and third parties. No matter how many stylesheets are included, all these styles cascade together in a single origin: the author style sheet.

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

¥Having styles from many sources cascade together, especially from teams that aren't working together, can create problems. Different teams may have different methodologies; one may have a best practice of reducing specificity, while another may have a standard of including an id in each selector.

特异性冲突可能会迅速升级。Web 开发者可以通过添加 !important 标志来创建 "快速解决"。虽然这可能感觉是一个简单的解决方案,但它通常只是将特殊性战争从正常声明转变为重要声明。

¥Specificity conflicts can escalate quickly. A web developer may create a "quick fix" by adding an !important flag. While this may feel like an easy solution, it often just moves the specificity war from normal to important declarations.

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

¥In the same way that cascade origins provide a balance of power between user, user-agents, and author styles, cascade layers provide a structured way to organize and balance concerns within a single origin as if each layer in an origin were a sub-origin. A layer can be created for each team, component, and third party, with style precedence based on layer order.

层内的规则级联在一起,而不与层外的样式规则竞争。级联层可以使整个样式表优先于其他样式表,而不必担心这些子源之间的特殊性。

¥Rules within a layer cascade together, without competing with style rules outside the layer. Cascade layers enable the prioritizing of entire stylesheets over other stylesheets, without having to worry about specificity between these sub-origins.

层优先级总是胜过选择器特异性。优先级为 "win" 的图层中的样式高于优先级较低的图层。丢失层中选择器的特异性是无关紧要的。特异性对于层内的竞争属性值仍然很重要,但层之间不存在特异性问题,因为仅考虑每个属性的最高优先级层。

¥Layer precedence always beats selector specificity. Styles in layers with precedence "win" over layers with less precedence. The specificity of a selector in a losing layer is irrelevant. Specificity still matters for competing property values within a layer, but there are no specificity concerns between layers because only the highest-priority layer for each property is considered.

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

¥Issues nested cascade layers can solve

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

¥Cascade layers allow the creation of nested layers. Each cascade layer can contain nested layers.

例如,可以将组件库导入到 components 层中。常规级联层会将组件库添加到作者原点,从而消除与其他作者风格的任何特异性冲突。在 components 层内,开发者可以选择定义各种主题,每个主题作为单独的嵌套层。这些嵌套主题层的顺序可以根据媒体查询来定义(请参阅下面的 图层创建和媒体查询 部分),例如视口大小或 orientation。这些嵌套层提供了一种创建不会根据特殊性发生冲突的主题的方法。

¥For example, a component library may be imported into a components layer. A regular cascade layer will add the component library to the author origin, removing any specificity conflicts with other author styles. Within the components layer, a developer can choose to define various themes, each as a separate nested layer. The order of these nested theme layers can be defined based on media queries (see the Layer creation and media queries section below), such as viewport size or orientation. These nested layers provide a way to create themes that don't conflict based on specificity.

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

¥The ability to nest layers is very useful for anybody who works on developing component libraries, frameworks, third-party widgets, and themes.

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

¥The ability to create nested layers also removes the worry of having conflicting layer names. We'll cover this in the nested layer section.

"作者可以创建层来表示元素默认值、第三方库、主题、组件、覆盖和其他样式问题,并且能够以显式方式重新排序层的级联,而无需更改每个层内的选择器或特殊性, 或者依靠出现顺序来解决跨层冲突。"

¥"Authors can create layers to represent element defaults, third-party libraries, themes, components, overrides, and other styling concerns—and are able to re-order the cascade of layers in an explicit way, without altering selectors or specificity within each layer, or relying on order of appearance to resolve conflicts across layers."

级联和继承规范.

¥—Cascading and Inheritance specification.

创建级联层

¥Creating cascade layers

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

¥Layers can be created using any one of the following methods:

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

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

¥All three methods create a layer if a layer with that name has not already been initialized. If no layer name is provided in the @layer at-rule or @import with layer(), a new anonymous (unnamed) layer is created.

注意:层的优先顺序是它们的创建顺序。不在层或 "无层次风格" 中的样式会一起级联成最终的隐式标签。

¥Note: The order of precedence of layers is the order in which they are created. Styles not in a layer, or "unlayered styles", cascade together into a final implicit label.

在讨论嵌套图层之前,让我们更详细地介绍一下创建图层的三种方法。

¥Let's cover the three ways of creating a layer in a little more detail before discussing nested layers.

命名层的 @layer 语句 at-rule

¥The @layer statement at-rule for named layers

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

¥The order of layers is set by the order in which the layers appear in your CSS. Declaring layers using @layer followed by the names of one or more layers without assigning any styles is one way to define the layer order.

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

¥The @layer CSS at-rule is used to declare a cascade layer and to define the order of precedence when there are multiple cascade layers. The following at-rule declares three layers, in the order listed:

css
@layer theme, layout, utilities;

你经常希望 CSS 的第一行是这个 @layer 声明(当然,层名称对你的站点有意义),以完全控制层顺序。

¥You will often want to have your first line of CSS be this @layer declaration (with layer names that make sense for your site, of course) to have full control over layer ordering.

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

¥If the above statement is the first line of a site's CSS, the layer order will be theme, layout, and utilities. If some layers were created prior to the above statement, as long as layers with these names don't already exist, these three layers will be created and added to the end of the list of existing layers. However, if a layer with the same name already exists, then the above statement will create only two new layers. For example, if layout already existed, only theme and utilities will be created, but the order of layers, in this case, will be layout, theme, and utilities.

命名和匿名层的 @layer 块规则

¥The @layer block at-rule for named and anonymous layers

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

¥Layers can be created using the block @layer at-rule. If an @layer at-rule is followed by an identifier and a block of styles, the identifier is used to name the layer, and the styles in this at-rule are added to the layer's styles. If a layer with the specified name does not already exist, a new layer will be created. If a layer with the specified name already exists, the styles are added to the previously existing layer. If no name is specified while creating a block of styles using @layer, the styles in the at-rule will be added to a new anonymous layer.

在下面的示例中,我们使用了四个块和一个内联 @layer at 规则。此 CSS 按列出的顺序执行以下操作:

¥In the example below, we've used four block and one inline @layer at-rules. This CSS does the following in the order listed:

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

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

/* 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: #000;
  }
}

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

在上面的 CSS 中,我们创建了五层:layout<anonymous(01)>themeutilities<anonymous(02)> – 按此顺序 - 第六个隐式非分层样式层包含在 body 样式块中。图层顺序是创建图层的顺序,未分层样式的隐式图层始终位于最后。创建后无法更改图层顺序。

¥In the above CSS, we created five layers: layout, <anonymous(01)>, theme, utilities, and <anonymous(02)> – in that order - with a sixth, implicit layer of unlayered styles contained in the body style block. The layer order is the order in which the layers are created, with the implicit layer of unlayered styles always being last. There is no way to change the layer order once created.

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

¥We assigned some styles to the layer named layout. If a named layer doesn't already exist, then specifying the name in an @layer at-rule, with or without assigning styles to the layer, creates the layer; this adds the layer to the end of the series of existing layer names. If the named layer already exists, all styles within the named block get appended to styles in the previously existing layer – specifying styles in a block by reusing an existing layer name does not create a new layer.

匿名图层是通过向图层指定样式而不命名图层来创建的。样式只能在创建未命名图层时添加到未命名图层。

¥Anonymous layers are created by assigning styles to a layer without naming the layer. Styles can be added to an unnamed layer only at the time of its creation.

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

¥Note: Subsequent use of @layer with no layer name creates additional unnamed layers; it does not append styles to a previously existing unnamed layer.

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

¥The @layer at-rule creates a layer, named or not, or appends styles to a layer if the named layer already exists. We called the first anonymous layer <anonymous(01)> and the second <anonymous(02)>, this is just so we can explain them. These are actually unnamed layers. There is no way to reference them or add additional styles to them.

在层外部声明的所有样式都在隐式层中连接在一起。在上面的示例代码中,第一个声明在 body 上设置了 color: #333 属性。这是在任何层之外声明的。普通的非分层声明优先于普通的分层声明,即使非分层样式的特异性较低并且按出现顺序排在第一位。这解释了为什么即使在代码块中首先声明了未分层的 CSS,包含这些未分层样式的隐式层也会优先,就像它是最后声明的层一样。

¥All styles declared outside of a layer are joined together in an implicit layer. In the example code above, the first declaration set the color: #333 property on body. This was declared outside of any layer. Normal unlayered declarations take precedence over normal layered declarations even if the unlayered styles have a lower specificity and come first in the order of appearance. This explains why even though the unlayered CSS was declared first in the code block, the implicit layer containing these unlayered styles takes precedence as if it was the last declared layer.

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

¥In the line @layer theme, layout, utilities;, in which a series of layers were declared, only the theme and utilities layers were created; layout was already created in the first line. Note that this declaration does not change the order of already created layers. There is currently no way to re-order layers once declared.

在下面的交互式示例中,我们将样式分配给两个图层,在此过程中创建它们并命名它们。因为它们已经存在,在第一次使用时创建,所以在最后一行声明它们不会执行任何操作。

¥In the following interactive example, we assign styles to two layers, creating them and naming them in the process. Because they already exist, being created when first used, declaring them on the last line does nothing.

尝试移动最后一行 @layer site, page;,使其成为第一行。会发生什么?

¥Try moving the last line, @layer site, page;, to make it the first line. What happens?

图层创建和媒体查询

¥Layer creation and media queries

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

¥If you define a layer using media or feature queries, and the media is not a match or the feature is not supported, the layer is not created. The example below shows how changing the size of your device or browser may change the layer order. In this example, we create the site layer only in wider browsers. We then assign styles to the page and site layers, in that order.

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

¥In wide screens, the site layer is declared in the first line, meaning site has less precedence than page. Otherwise, site has precedence over page because it is declared later on narrow screens. If that doesn't work, try changing the 50em in the media query to 10em or 100em.

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

¥Importing style sheets into named and anonymous layers with @import

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

¥The @import rule allows users to import style rules from other style sheets either directly into a CSS file or into a <style> element.

导入样式表时,必须在样式表或 <style> 块中的任何 CSS 样式之前定义 @import 语句。@import 语句必须位于第一个,位于任何样式之前,但前面可以有 @layer at 规则,用于创建一个或多个图层而不向图层分配任何样式。(@import 之前也可以有 @charset 规则。)

¥When importing stylesheets, the @import statement must be defined before any CSS styles within the stylesheet or <style> block. The @import statement must come first, before any styles, but can be preceded by an @layer at-rule that creates one or more layers without assigning any styles to the layers. (@import can also be preceded by an @charset rule.)

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

¥You can import a stylesheet into a named layer, a nested named layer, or an anonymous layer. The following layer imports the style sheets into a components layer, a nested dialog layer within the components layer, and an un-named layer, respectively:

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

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

¥You can import more than one CSS file into a single layer. The following declaration imports two separate files into a single social layer:

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

你可以使用 媒体查询特性查询 根据特定条件导入样式并创建图层。以下仅在浏览器支持 display: ruby 的情况下将样式表导入到 international 图层中,并且导入的文件取决于屏幕的宽度。

¥You can import styles and create layers based on specific conditions using media queries and feature queries. The following imports a style sheet into an international layer only if the browser supports display: ruby, and the file being imported is dependent on the width of the screen.

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

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

¥Note: There is no equivalent of the <link> method of linking stylesheets. Use @import to import a stylesheet into a layer when you can't use @layer within the stylesheet.

嵌套级联层概述

¥Overview of nested cascade layers

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

¥Nested layers are layers within a named or an anonymous layer. Each cascade layer, even an anonymous one, can contain nested layers. Layers imported into another layer become nested layers within that layer.

嵌套层的优点

¥Advantages of nesting layers

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

¥The ability to nest layers enables teams to create cascade layers without worrying about whether other teams will import them into a layer. Similarly, nesting enables you to import third-party style sheets into a layer without worrying if that style sheet itself has layers. Because layers can be nested, you don't have to worry about having conflicting layer names between external and internal style sheets.

创建嵌套级联层

¥Creating nested cascade layers

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

¥Nested layers can be created using the same methods as described for regular layers. For example, they can be created using @layer at-rule followed by the names of one or more layers, using a dot notation. Multiple dots and layer names signify multiple nesting.

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

¥If you nest a block @layer at-rule inside another block @layer at-rule, with or without a name, the nested block becomes a nested layer. Similarly, when a style sheet is imported with an @import declaration containing the layer keyword or layer() function, the styles get assigned to that named or anonymous layer. If the @import statement contains layers, those layers become nested layers within that anonymous or named layer.

让我们看下面的例子:

¥Let's look at the following example:

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

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

¥In the first line, we import components-lib.css into the components layer. If that file contains any layers, named or not, those layers become nested layers within the components layer.

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

¥The second line imports narrowtheme.css into the narrow layer, which is a sub-layer of components. The nested components.narrow gets created as the last layer within the components layer, unless components-lib.css already contains a narrow layer, in which case, the contents of narrowtheme.css would be appended to the components.narrow nested layer. Additional nested named layers can be added to the components layer using the pattern components.<layerName>. As mentioned before, unnamed layers can be created but they cannot be accessed subsequently.

让我们看另一个例子,我们 layers1.css 导入命名图层 使用以下语句:

¥Let's look at another example, where we import layers1.css into a named layer using the following statement:

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

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

¥This will create a single layer named example containing some declarations and five nested layers - example.layout, example.<anonymous(01)>, example.theme, example.utilities, and example.<anonymous(02)>.

要将样式添加到命名嵌套图层,请使用点符号:

¥To add styles to a named nested layer, use the dot notation:

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

根据层的顺序确定优先级

¥Determining the precedence based on the order of layers

层的顺序决定了它们的优先顺序。因此,层的顺序非常重要。与级联按来源和重要性排序的方式相同,级联按来源层和重要性对每个 CSS 声明进行排序。

¥The order of layers determines their order of precedence. Therefore, the order of layers is very important. In the same way as the cascade sorts by origin and importance, the cascade sorts each CSS declaration by origin layer and importance.

规则级联层的优先顺序

¥Precedence order of regular cascade layers

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

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

¥The above code creates two named layers (C.css styles get appended to the implicit layer of unlayered styles). Let us assume that the three files (A.css, B.css, and C.css) do not contain any additional layers within them. The following list shows where styles declared inside and outside of these files will be sorted from least (1) precedence to highest (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 中声明的正常样式将被列表中的任何后续样式覆盖。

¥Normal styles declared inside layers receive the lowest priority and are sorted by the order in which the layers were created. Normal styles in the first created layer have the lowest precedence, and normal styles in the layer created last have the highest precedence among the layers. In other words, normal styles declared within firstLayer will be overridden by any subsequent stylings on the list if any conflicts exist.

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

¥Next up are any styles declared outside of layers. The styles in C.css were not imported into a layer and will override any conflicting styles from firstLayer and secondLayer. Styles not declared in a layer always have higher precedence than styles that are declared inside a layer (with the exception of important styles).

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

¥Inline styles are declared using the style attribute. Normal styles declared in this way will take precedence over normal styles found in the unlayered and layered style sheets (firstLayer – A.css, secondLayer – B.css, and C.css).

动画样式的优先级高于所有普通样式,包括内联普通样式。

¥Animating styles have higher precedence than all normal styles, including inline normal styles.

重要样式(即包含 !important 标志的属性值)优先于我们列表中之前提到的任何样式。它们以与正常样式相反的顺序排序。在层外部声明的任何重要样式的优先级都低于在层内声明的优先级。图层中找到的重要样式也会按照图层创建的顺序进行排序。对于重要的样式,在声明的图层中,最后创建的图层的优先级最低,最先创建的图层的优先级最高。

¥Important styles, that is, property values that include the !important flag, take precedence over any styles previously mentioned in our list. They are sorted in reverse order of normal styles. Any important styles declared outside of a layer have less precedence than those declared within a layer. Important styles found within layers are also sorted in order of layer creation. For important styles, the last created layer has the lowest precedence, and the first created layer has the highest precedence among declared layers.

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

¥Inline important styles again have higher precedence than important styles declared elsewhere.

过渡样式具有最高优先级。当转换普通属性值时,它优先于所有其他属性值声明,甚至是内联重要样式;但仅限于过渡期间。

¥Transitioning styles have the highest precedence. When a normal property value is being transitioned, it takes precedence over all other property value declarations, even inline important styles; but only while transitioning.

在此示例中,有两个没有样式的内联图层 AB、一个未分层样式块以及命名图层 AB 中的两个样式块。

¥In this example, there are two inline layers A and B without styles, a block of unlayered styles, and two blocks of styles in named layers A and B.

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

¥The inline styles added on the h1 element using the style attribute, set a normal color and an important background-color. Normal inline styles override all layered and unlayered normal styles. Important inline styles override all layered and unlayered normal and important author styles. There is no way for author styles to override important inline styles.

普通 text-decoration 和重要 box-shadow 不是 style 内联样式的一部分,因此可以被覆盖。对于普通的非内联样式,非分层样式优先。对于重要的样式,图层顺序也很重要。虽然普通的非分层样式会覆盖图层中设置的所有普通样式,但对于重要的样式,优先顺序是相反的;未分层的重要样式的优先级低于分层样式。

¥The normal text-decoration and important box-shadow are not part of the style inline styles and can therefore be overridden. For normal non-inline styles, unlayered styles have precedence. For important styles, layer order matters too. While normal unlayered styles override all normal styles set in a layer, with important styles, the precedence order is reversed; unlayered important styles have lower precedence than layered styles.

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

¥The two styles declared only within layers are font-style, with normal importance, and font-weight with an !important flag. For normal styles, the B layer, declared last, overrides styles in the earlier declared layer A. For normal styles, later layers have precedence over earlier layers. The order of precedence is reversed for important styles. For the important font-weight declarations, layer A, being declared first, has precedence over the last declared layer B.

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

¥You can reverse the layer order by changing the first line from @layer A, B; to @layer B, A;. Try that. Which styles get changed by this, and which stay the same? Why?

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

¥The order of layers is set by the order in which the layers appear in your CSS. In our first line, we declared layers without assigning any styles using @layer followed by the names of our layers, ending with a semi-colon. Had we omitted this line, the results would have been the same. Why? We assigned style rules in named @layer blocks in the order A then B. The two layers were created in that first line. Had they not been, these rule blocks would have created them, in that order.

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

¥We included that first line for two reasons: first so you could easily edit the line and switch the order, and second because often you'll find declaring the order layer up front to be the best practice for your layer order management.

总结一下:

¥To summarize:

  • 层的优先顺序是创建层的顺序。
  • 一旦创建,就无法更改图层顺序。
  • 普通样式的图层优先级是创建图层的顺序。
  • 无分层的普通样式优先于普通的分层样式。
  • 重要样式的图层优先级是相反的,较早创建的图层具有优先权。
  • 所有分层的重要样式都优先于未分层的重要(和普通)样式。
  • 普通内联样式优先于所有普通样式,无论是否分层。
  • 重要的内联样式优先于所有其他样式,过渡的样式除外。
  • 作者样式无法覆盖重要的内联样式(除了过渡它们,这是暂时的)。

嵌套级联层的优先顺序

¥Precedence order of nested cascade layers

嵌套层的级联优先顺序与常规层类似,但包含在层内。优先顺序基于嵌套层创建的顺序。图层中的非嵌套样式优先于嵌套普通样式,重要样式的优先顺序相反。嵌套层之间的特异性权重并不重要,但对于嵌套层内的冲突样式确实很重要。

¥The cascade precedence order for nested layers is similar to that of regular layers, but contained within the layer. The precedence order is based on the order of nested layer creation. Non-nested styles in a layer have precedence over nested normal styles, with the precedence order reversed for important styles. Specificity weight between nested layers does not matter, though it does matter for conflicting styles within a nested layer.

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

¥The following creates and adds styles to the components layer, components.narrow nested layer, and components.wide nested layer:

html
<div>Text</div>
css
div {
  height: 150px;
  width: 150px;
  margin: 1rem;
  padding: 1rem;
  font-size: 3rem;
}
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%;
  }
}

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

¥Here's a summary of the properties that are used and why each declaration is applied:

  • background-color:因为未分层的普通样式优先于分层的普通样式,所以 wheat 颜色获胜。
  • border:因为在层内非嵌套样式优先于普通嵌套样式,所以 red 颜色获胜。
  • color:对于重要样式,分层样式优先于非分层样式,并且较早声明的图层中的重要样式优先于较晚声明的图层。在此示例中,嵌套层创建的顺序是 components.narrow,然后是 components.wide,因此 components.narrow 中的重要样式优先于 components.wide 中的重要样式,这意味着 purple 颜色获胜。
  • border-radius:该属性仅在嵌套层中设置,因此按声明顺序 20% radius 获胜。

测试你的技能!

¥Test your skills!

你已读完本文,但你还记得最重要的信息吗?在继续之前,你可以找到一些进一步的测试来验证你是否已保留此信息 - 请参阅 测试你的技能:级联,任务 2

¥You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see Test your skills: The Cascade, Task 2.

概括

¥Summary

如果你理解了本文的大部分内容,那么做得很好 — 你现在已经熟悉了 CSS 级联层的基原生制。接下来,我们将详细了解 盒子模型

¥If you understood most of this article, then well done — you're now familiar with the fundamental mechanics of CSS cascade layers. Next up, we'll look at the box model in detail.