Skip to main content Skip to docs navigation

Learn CSS Cascade in web app development. This guide will cover general best practices as demonstrated through the CSS cascade and some tips on how user agents combine property values originating from different sources from the start in detail.

On this page

Cascade, specificity, and inheritance

The aim of this lesson is to develop your understanding of some of the most fundamental concepts of CSS — the cascade, specificity, and inheritance — which control how CSS is applied to HTML and how conflicts between style declarations are resolved.

While working through this lesson may seem less relevant immediately and a little more academic than some other parts of the course, an understanding of these concepts will save you from a lot of pain later on! We encourage you to work through this section carefully and check that you understand the concepts before moving on.

Prerequisites: Basic software installed , basic knowledge of working with files , HTML basics (study Introduction to HTML ), and an idea of how CSS works (study CSS first steps .)
Objective: To learn about the cascade and specificity, and how inheritance works in CSS.

Conflicting rules

CSS stands for Cascading Style Sheets , and that first word cascading is incredibly important to understand — the way that the cascade behaves is key to understanding CSS.

At some point, you will be working on a project and you will find that the CSS you thought should be applied to an element is not working. Often, the problem is that you create two rules that apply different values of the same property to the same element. Cascade and the closely-related concept of specificity are mechanisms that control which rule applies when there is such a conflict. The rule that's styling your element may not be the one you expect, so you need to understand how these mechanisms work.

Also significant here is the concept of inheritance , which means that some CSS properties by default inherit values set on the current element's parent element and some don't. This can also cause some behavior that you might not expect.

Let's start by taking a quick look at the key things we are dealing with, then we'll look at each in turn and see how they interact with each other and your CSS. These can seem like a tricky set of concepts to understand. As you get more practice writing CSS, the way it works will become more obvious to you.

Cascade

Stylesheets cascade — at a very simple level, this means that the origin, the cascade layer, and the order of CSS rules matter. When two rules from the same cascade layer apply and both have equal specificity, the one that is defined last in the stylesheet is the one that will be used.

In the below example, we have two rules that could apply to the <h1 > element. The <h1 > content ends up being colored blue. This is because both the rules are from the same source, have an identical element selector, and therefore, carry the same specificity, but the last one in the source order wins.

Specificity

Specificity is the algorithm that the browser uses to decide which property value is applied to an element. If multiple style blocks have different selectors that configure the same property with different values and target the same element, specificity decides the property value that gets applied to the element. Specificity is basically a measure of how specific a selector's selection will be:

  • An element selector is less specific; it will select all elements of that type that appear on a page, so it has less weight. Pseudo-element selectors have the same specificity as regular element selectors.
  • A class selector is more specific; it will select only the elements on a page that have a specific class attribute value, so it has more weight. Attribute selectors and pseudo-classes have the same weight as a class.

Below, we again have two rules that could apply to the <h1 > element. The <h1 > content below ends up being colored red because the class selector main-heading gives its rule a higher specificity. So even though the rule with the <h1 > element selector appears further down in the source order, the one with the higher specificity, defined using the class selector, will be applied.

We'll explain the specificity algorithm later on.

Inheritance

Inheritance also needs to be understood in this context — some CSS property values set on parent elements are inherited by their child elements, and some aren't.

For example, if you set a color and font-family on an element, every element inside it will also be styled with that color and font, unless you've applied different color and font values directly to them.

Some properties do not inherit — for example, if you set a width of 50% on an element, all of its descendants do not get a width of 50% of their parent's width. If this was the case, CSS would be very frustrating to use!

Note: On datarist CSS property reference pages, you can find a technical information box called "Formal definition", which lists a number of data points about that property, including whether it is inherited or not. See the color property Formal definition section as an example.

Understanding how the concepts work together

These three concepts (cascade, specificity, and inheritance) together control which CSS applies to what element. In the sections below, we'll see how they work together. It can sometimes seem a little bit complicated, but you will start to remember them as you get more experienced with CSS, and you can always look up the details if you forget! Even experienced developers don't remember all the details.

The following video shows how you can use the Firefox DevTools to inspect a page's cascade, specificity, and more:

Understanding inheritance

We'll start with inheritance. In the example below, we have a <ul > element with two levels of unordered lists nested inside it. We have given the outer <ul > a border, padding, and font color.

The color property is an inherited property. So, the color property value is applied to the direct children and also to the indirect children — the immediate child <li > s and those inside the first nested list. We have then added the class special to the second nested list and applied a different color to it. This then inherits down through its children.

Properties like width (as mentioned earlier), margin , padding , and border are not inherited properties. If a border were to be inherited by the children in this list example, every single list and list item would gain a border — probably not an effect we would ever want!

Though every CSS property page lists whether or not the property is inherited, you can often guess the same intuitively if you know what aspect the property value will style.

Controlling inheritance

CSS provides five special universal property values for controlling inheritance. Every CSS property accepts these values.

inherit

Sets the property value applied to a selected element to be the same as that of its parent element. Effectively, this "turns on inheritance".

initial

Sets the property value applied to a selected element to the initial value of that property.

revert

Resets the property value applied to a selected element to the browser's default styling rather than the defaults applied to that property. This value acts like unset in many cases.

revert-layer

Resets the property value applied to a selected element to the value established in a previous cascade layer .

unset

Resets the property to its natural value, which means that if the property is naturally inherited it acts like inherit , otherwise it acts like initial .

Note: See Origin types for more information on each of these and how they work.

We can look at a list of links and explore how universal values work. The live example below allows you to play with the CSS and see what happens when you make changes. Playing with code really is the best way to better understand HTML and CSS.

For example:

  1. The second list item has the class my-class-1 applied. This sets the color of the <a > element nested inside to inherit . If you remove the rule, how does it change the color of the link?
  2. Do you understand why the third and fourth links are the color that they are? The third link is set to initial , which means it uses the initial value of the property (in this case black) and not the browser default for links, which is blue. The fourth is set to unset which means that the link text uses the color of the parent element, green.
  3. Which of the links will change color if you define a new color for the <a > element — for example a { color: red; } ?
  4. After reading the next section on resetting all properties, come back and change the color property to all . Notice how the second link is on a new line and has a bullet. What properties do you think were inherited?

Resetting all property values

The CSS shorthand property all can be used to apply one of these inheritance values to (almost) all properties at once. Its value can be any one of the inheritance values (inherit , initial , revert , revert-layer , or unset ). It's a convenient way to undo changes made to styles so that you can get back to a known starting point before beginning new changes.

In the below example, we have two blockquotes. The first has styling applied to the blockquote element itself. The second has a class applied to the blockquote, which sets the value of all to unset .

Try setting the value of all to some of the other available values and observe what the difference is.

Understanding the cascade

We now understand that inheritance is why a paragraph nested deep in the structure of your HTML is the same color as the CSS applied to the body. From the introductory lessons, we have an understanding of how to change the CSS applied to something at any point in the document — whether by assigning CSS to an element or by creating a class. We will now look at how cascade defines which CSS rules apply when more than one style block apply the same property, but with different values, to the same element.

There are three factors to consider, listed here in increasing order of importance. Later ones overrule earlier ones:

  1. Source order
  2. Specificity
  3. Importance

We will look at these to see how browsers figure out exactly what CSS should be applied.

Source order

We have already seen how source order matters to the cascade. If you have more than one rule, all of which have exactly the same weight, then the one that comes last in the CSS will win. You can think of this as: the rule that is nearer the element itself overwrites the earlier ones until the last one wins and gets to style the element.

Source order only matters when the specificity weight of the rules is the same, so let's look at specificity:

Specificity

You will often run into a situation where you know that a rule comes later in the stylesheet, but an earlier, conflicting rule is applied. This happens because the earlier rule has a higher specificity — it is more specific, and therefore, is being chosen by the browser as the one that should style the element.

As we saw earlier in this lesson, a class selector has more weight than an element selector, so the properties defined in the class style block will override those defined in the element style block.

Something to note here is that although we are thinking about selectors and the rules that are applied to the text or component they select, it isn't the entire rule that is overwritten, only the properties that are declared in multiple places.

This behavior helps avoid repetition in your CSS. A common practice is to define generic styles for the basic elements, and then create classes for those that are different. For example, in the stylesheet below, we have defined generic styles for level 2 headings, and then created some classes that change only some of the properties and values. The values defined initially are applied to all headings, then the more specific values are applied to the headings with the classes.

Let's now have a look at how the browser will calculate specificity. We already know that an element selector has low specificity and can be overwritten by a class. Essentially a value in points is awarded to different types of selectors, and adding these up gives you the weight of that particular selector, which can then be assessed against other potential matches.

The amount of specificity a selector has is measured using three different values (or components), which can be thought of as ID, CLASS, and ELEMENT columns in the hundreds, tens, and ones place:

  • Identifiers : Score one in this column for each ID selector contained inside the overall selector.
  • Classes : Score one in this column for each class selector, attribute selector, or pseudo-class contained inside the overall selector.
  • Elements : Score one in this column for each element selector or pseudo-element contained inside the overall selector.

Note: The universal selector ( * ), combinators (+ , > , ~ , ' '), and specificity adjustment selector ( :where() ) along with its parameters, have no effect on specificity.

The negation ( :not() ), relational selector ( :has() ), the matches-any ( :is() ) pseudo-classes, and CSS nesting themselves don't add to specificity, but their parameters or nested rules do. The specificity weight that each contributes to the specificity algorithm is the specificity weight of the selector in the parameter or nested rule with the greatest weight.

The following table shows a few isolated examples to get you in the mood. Try going through these, and make sure you understand why they have the specificity that we have given them. We've not covered selectors in detail yet, but you can find details of each selector on the datarist selectors reference .

Selector Identifiers Classes Elements Total specificity
h1 0 0 1 0-0-1
h1 + p::first-letter 0 0 3 0-0-3
li >a[href*="en-US"] >.inline-warning 0 2 2 0-2-2
#identifier 1 0 0 1-0-0
button:not(#mainBtn, .cta ) 1 0 1 1-0-1

Before we move on, let's look at an example in action.

So what's going on here? First of all, we are only interested in the first seven rules of this example, and as you'll notice, we have included their specificity values in a comment before each one.

  • The first two selectors are competing over the styling of the link's background color. The second one wins and makes the background color blue because it has an extra ID selector in the chain: its specificity is 2-0-1 vs. 1-0-1.
  • Selectors 3 and 4 are competing over the styling of the link's text color. The second one wins and makes the text white because although it has one less element selector, the missing selector is swapped out for a class selector, which has more weight than infinity element selectors. The winning specificity is 1-1-3 vs. 1-0-4.
  • Selectors 5–7 are competing over the styling of the link's border when hovered. Selector 6 clearly loses to selector 5 with a specificity of 0-2-3 vs. 0-2-4; it has one fewer element selectors in the chain. Selector 7, however, beats both selectors 5 and 6 because it has the same number of sub-selectors in the chain as selector 5, but an element has been swapped out for a class selector. So the winning specificity is 0-3-3 vs. 0-2-3 and 0-2-4.

Note: Each selector type has its own level of specificity that cannot be overwritten by selectors with a lower specificity level. For example, a million class selectors combined would not be able to overwrite the specificity of one id selector.

The best way to evaluate specificity is to score the specificity levels individually starting from the highest and moving on to the lowest when necessary. Only when there is a tie between selector scores within a specificity column do you need to evaluate the next column down; otherwise, you can disregard the lower specificity selectors since they can never overwrite the higher specificity selectors.

Inline styles

Inline styles, that is, the style declaration inside a style attribute, take precedence over all normal styles, no matter the specificity. Such declarations don't have selectors, but their specificity can be construed as 1-0-0-0; always more than any other specificity weight no matter how many IDs are in the selectors.

!important

There is a special piece of CSS that you can use to overrule all of the above calculations, even inline styles - the !important flag. However, you should be very careful while using it. This flag is used to make an individual property and value pair the most specific rule, thereby overriding the normal rules of the cascade, including normal inline styles.

Note: It is useful to know that the !important flag exists so that you know what it is when you come across it in other people's code. However, we strongly recommend that you never use it unless you absolutely have to. The !important flag changes the way the cascade normally works, so it can make debugging CSS problems really hard to work out, especially in a large stylesheet.

Take a look at this example where we have two paragraphs, one of which has an ID.

Let's walk through this to see what's happening — try removing some of the properties to see what happens if you are finding it hard to understand:

  1. You'll see that the third rule's color and padding values have been applied, but the background-color hasn't. Why? Really, all three should surely apply because rules later in the source order generally override earlier rules.
  2. However, the rules above it win because class selectors have higher specificity than element selectors.
  3. Both elements have a class of better , but the 2nd one has an id of winning too. Since IDs have an even higher specificity than classes (you can only have one element with each unique ID on a page, but many elements with the same class — ID selectors are very specific in what they target), the red background color and the 1px black border should both be applied to the 2nd element, with the first element getting the gray background color, and no border, as specified by the class.
  4. The 2nd element does get the red background color, but no border. Why? Because of the !important flag in the second rule. Adding the !important flag after border: none means that this declaration will win over the border value in the previous rule, even though the ID selector has higher specificity.

Note: The only way to override an important declaration is to include another important declaration with the same specificity later in the source order, or one with higher specificity, or to include an important declaration in a prior cascade layer (we haven't covered cascade layers yet).

One situation in which you may have to use the !important flag is when you are working on a CMS where you can't edit the core CSS modules, and you really want to override an inline style or an important declaration that can't be overridden in any other way. But really, don't use it if you can avoid it.

The effect of CSS location

Finally, it is important to note that the precedence of a CSS declaration depends on what stylesheet and cascade layer it is specified in.

It is possible for users to set custom stylesheets to override the developer's styles. For example, a visually impaired user might want to set the font size on all web pages they visit to be double the normal size to allow for easier reading.

It is also possible to declare developer styles in cascade layers: you can make non-layered styles override styles declared in layers or you can make styles declared in later layers override styles from earlier declared layers. For example, as a developer you may not be able to edit a third-party stylesheet, but you can import the external stylesheet into a cascade layer so that all of your styles easily override the imported styles without worrying about third-party selector specificity.

Order of overriding declarations

Conflicting declarations will be applied in the following order, with later ones overriding earlier ones:

  1. Declarations in user agent style sheets (e.g., the browser's default styles, used when no other styling is set).
  2. Normal declarations in user style sheets (custom styles set by a user).
  3. Normal declarations in author style sheets (these are the styles set by us, the web developers).
  4. Important declarations in author style sheets.
  5. Important declarations in user style sheets.
  6. Important declarations in user agent style sheets.

Note: The order of precedence is inverted for styles flagged with !important . It makes sense for web developers' stylesheets to override user stylesheets, so the design can be kept as intended; however, sometimes users have good reasons to override web developer styles, as mentioned above, and this can be achieved by using !important in their rules.

Order of cascade layers

Even though cascade layers is an advanced topic and you might not use this feature right away, it's important to understand how layers cascade.

When you declare CSS in cascade layers, the order of precedence is determined by the order in which the layers are declared. CSS styles declared outside of any layer are combined together, in the order in which those styles are declared, into an unnamed layer, as if it were the last declared layer. With competing normal (not important) styles, later layers take precedence over earlier defined layers. For styles flagged with !important , however, the order is reversed, with important styles in earlier layers taking precedence over important styles declared in subsequent layers or outside of any layer. Inline styles take precedence over all author styles, no matter the layer.

When you have multiple style blocks in different layers providing competing values for a property on a single element, the order in which the layers are declared determines the precedence. Specificity between layers doesn't matter, but specificity within a single layer still does.

Let's discuss a few things from the above example to understand what's happening. Two layers have been declared, firstLayer and secondLayer , in that order. Even though the specificity in secondLayer is the highest, no properties from that declaration are used. Why? Because non-layered normal styles take precedence over layered normal styles, no matter the specificity, and important layered styles take precedence over important styles declared in later layers, again, no matter the specificity.

If you change the first line of CSS in this example to read @layer secondLayer, firstLayer; , you will change the layer declaration order, and all the important styles from firstLayer will be changed to their respective values in secondLayer .

Scoping proximity

Another advanced topic that you might not use right away but may need to understand in the future is @scope . This is an at-rule that enables you to create a block of rules that will only apply to a specific subsection of the HTML on your page. For example, you can specify styles that will only apply to <img > elements when they're nested inside elements that have a feature class:

css
                                        
                                            
                                                @scope
                                                (
                                                .feature)
                                            
                                            {
                                            img
                                            {
                                            border
                                            :
                                            2px solid black;
                                            display
                                            :
                                            block;
                                            }
                                            }
                                        
                                    

Scoping proximity is the mechanism that resolves conflicts between scoped elements. Scoping proximity states that when two scopes have conflicting styles, the style with the smallest number of hops up the DOM tree hierarchy to the scope root wins. See How @scope conflicts are resolved for more details and an example.

Note: Scoping proximity overrules source order but is itself overridden by other, higher-priority criteria such as importance , layers , and specificity .

Test your skills!

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 .

Summary

If you understood most of this article, then well done — you've started getting familiar with the fundamental mechanics of CSS. Next up, we'll take a deeper look at Cascade Layers .

If you didn't fully understand the cascade, specificity, and inheritance, then don't worry! This is definitely the most complicated thing we've covered so far in the course and is something that even professional web developers sometimes find tricky. We'd advise that you return to this article a few times as you continue through the course, and keep thinking about it.

Refer back here if you start to come across strange issues with styles not applying as expected. It could be a specificity issue.

Cascade layers

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 .

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.

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 .

Prerequisites: An idea of how CSS works, including cascade and specificity (study CSS first steps and Cascade, specificity, and inheritance ).
Objective: To learn how cascade layers work.

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.

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.

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

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. Relevance: Find all the declaration blocks with a selector match for each element.
  2. Importance: Sort rules based on whether they are normal or important. Important styles are those that have the !important flag set.
  3. Origin: Within each of the two importance buckets, sort rules by author, user, or user-agent origin.
  4. Cascade layers: Within each of the six origin importance buckets, sort by cascade layer. The layer order for normal declarations is from the first layer created to the last, followed by unlayered normal styles. This order is inverted for important styles, with unlayered important styles having the lowest precedence.
  5. Specificity: For competing styles in the origin layer with precedence, sort declarations by specificity .
  6. Scoping proximity : When two selectors in the origin layer with precedence have the same specificity, the property value within scoped rules with the smallest number of hops up the DOM hierarchy to the scope root wins. See How @scope conflicts are resolved for more details and an example.
  7. Order of appearance: When two selectors in the origin layer with precedence have the same specificity and scope proximity, the property value from the last declared selector with the highest specificity 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

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. user-agent normal styles
  2. user normal styles
  3. author normal styles
  4. styles being animated
  5. author important styles
  6. user important styles
  7. user-agent important styles
  8. styles being transitioned

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

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.

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.

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.

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.

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.

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.

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:

  • The @layer statement at-rule, declaring layers using @layer followed by the names of one or more layers. This creates named layers without assigning any styles to them.
  • The @layer block at-rule, in which all styles within a block are added to a named or unnamed layer.
  • The @import rule with the layer keyword or layer() function, which assigns the contents of the imported file into that layer.

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.

The @layer statement at-rule for named layers

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 .

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;
                                            
                                        
                                    

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.

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 .

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

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.

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. Creates a named layout layer
  2. Creates an unnamed, anonymous layer
  3. Declares a list of three layers and creates only two new layers, theme and utilities , because layout already exists
  4. Adds additional styles to the already existing layout layer
  5. Creates a second unnamed, anonymous layer
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;
                                            }
                                            }
                                        
                                    

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.

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.

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

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.

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.

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.

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

Layer creation and media queries

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.

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 .

Importing style sheets into named and anonymous layers with @import

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

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.)

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
                                                (
                                                )
                                                ;
                                            
                                        
                                    

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)
                                                ;
                                            
                                        
                                    

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)
                                                ;
                                            
                                        
                                    

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

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.

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)
                                                ;
                                            
                                        
                                    

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.

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.

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)
                                                ;
                                            
                                        
                                    

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

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)
                                                
                                                ;
                                            
                                        
                                    

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 normal styles (A.css )
  2. secondLayer normal styles (B.css )
  3. unlayered normal styles (C.css )
  4. inline normal styles
  5. animating styles
  6. unlayered important styles (C.css )
  7. secondLayer important styles (B.css )
  8. firstLayer important styles (A.css )
  9. inline important styles
  10. transitioning styles

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.

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).

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 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.

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 .

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.

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.

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 .

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?

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:

  • The order of precedence of layers is the order in which the layers are created.
  • Once created, there is no way to change the layer order.
  • Layer precedence for normal styles is the order in which the layers are created.
  • Unlayered normal styles have precedence over normal layered styles.
  • Layer precedence for important styles is reversed, with earlier created layers having precedence.
  • All layered important styles have precedence over unlayered important (and normal) styles.
  • Normal inline styles take precedence over all normal styles, layered or not.
  • Important inline styles take precedence over all other styles, with the exception of styles being transitioned.
  • There is no way for author styles to override important inline styles (other than transitioning them, which is temporary).

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.

The following creates and adds styles to the components layer and components.narrow nested layer and creates and appends styles to a new components.wide layer:

css
                                        
                                            
                                                @import
                                                
                                                    url
                                                    (
                                                    "components-lib.css"
                                                    )
                                                
                                                layer
                                                (
                                                components)
                                                ;
                                            
                                            
                                                @import
                                                
                                                    url
                                                    (
                                                    "narrowtheme.css"
                                                    )
                                                
                                                layer
                                                (
                                                components.narrow)
                                                ;
                                            
                                            
                                                @layer
                                                components
                                            
                                            {
                                            :root
                                            {
                                            --theme
                                            :
                                            red;
                                            font-family
                                            :
                                            serif !important
                                            ;
                                            }
                                            }
                                            
                                                @layer
                                                components.narrow
                                            
                                            {
                                            :root
                                            {
                                            --theme
                                            :
                                            blue;
                                            font-family
                                            :
                                            sans-serif !important
                                            ;
                                            }
                                            }
                                            
                                                @layer
                                                components.wide
                                            
                                            {
                                            :root
                                            {
                                            --theme
                                            :
                                            purple;
                                            font-family
                                            :
                                            cursive !important
                                            ;
                                            }
                                            }
                                        
                                    

Because unlayered normal styles have precedence over layered normal styles, and within a layer, non-nested styles have precedence over normal nested styles, red wins over the other theme colors.

With important styles, layered styles take precedence over unlayered styles, with important styles in earlier declared layers having precedence over later declared layers. In this example, the order of nested layer creation is components.narrow , then components.wide , so important styles in components.narrow have precedence over important styles in components.wide , meaning sans-serif wins.

Test your skills!

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

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.

Updated on April 20, 2024 by Datarist.