The CSS Podcast - 004: The Cascade
CSS stands for Cascading Stylesheets. The cascade is the algorithm for solving conflicts where multiple CSS rules apply to an HTML element. It's the reason that the text of the button styled with the following CSS will be blue.
button {
color: red;
}
button {
color: blue;
}
Understanding the cascade algorithm helps you understand how the browser resolves conflicts like this. The cascade algorithm is split into 4 distinct stages.
- Position and order of appearance: the order of which your CSS rules appear
- Specificity: an algorithm which determines which CSS selector has the strongest match
- Origin: the order of when CSS appears and where it comes from, whether that is a browser style, CSS from a browser extension, or your authored CSS
- Importance: some CSS rules are weighted more heavily than others,
especially with the
!important
rule type
Position and order of appearance
The order in which your CSS rules appear and how they appear is taken into consideration by the cascade while it calculates conflict resolution.
The demo right at the start of this lesson is the most straightforward example of position. There are two rules that have selectors of identical specificity, so the last one to be declared won.
Styles can come from various sources on an HTML page,
such as a <link>
tag,
an embedded <style>
tag,
and inline CSS as defined in an element's style
attribute.
If you have a <link>
that includes CSS at the top of your HTML page,
then another <link>
that includes CSS at the bottom of your page: the bottom <link>
will have the most specificity.
The same thing happens with embedded <style>
elements, too.
They get more specific, the further down the page they are.
This ordering also applies to embedded <style>
elements.
If they are declared before a <link>
,
the linked stylesheet's CSS will have the most specificity.
An inline style
attribute with CSS declared in it will override all other CSS,
regardless of its position, unless a declaration has !important
defined.
Position also applies in the order of your CSS rule.
In this example, the element will have a purple background because background: purple
was declared last.
Because the green background was declared before the purple background, it is now ignored by the browser.
.my-element {
background: green;
background: purple;
}
Being able to specify two values for the same property
can be a simple way to create fallbacks for browsers that do not support a particular value.
In this next example, font-size
is declared twice.
If clamp()
is supported in the browser,
then the previous font-size
declaration will be discarded.
If clamp()
isn't supported by the browser,
the initial declaration will be honored, and the font-size will be 1.5rem
.my-element {
font-size: 1.5rem;
font-size: clamp(1.5rem, 1rem + 3vw, 2rem);
}
Check your understanding
Test your knowledge of the cascade
If you have the following HTML on your page:
<!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="https://web.dev/styles.css" /> </head> <body> <button>I am a button</button> <style> button { background: pink; } </style> </body> </html>
Inside styles.css
, is the following CSS rule:
button { background: yellow; }
What color is the button's background?
<style>
origin is further down the page than the
<link>
tag, so while the specificity of button
is the same, the
position of the style rule makes it win.
Specificity
Specificity is an algorithm which determines which CSS selector is the most specific, using a weighting or scoring system to make those calculations. By making a rule more specific, you can cause it to be applied even if some other CSS that matches the selector appears later in the CSS.
In the next lesson you can learn the details of how specificity is calculated, however keeping a few things in mind will help you avoid too many specificity issues.
CSS targeting a class on an element will make that rule more specific,
and therefore seen as more important to be applied,
than CSS targeting the element alone.
This means that with the following CSS,
the h1
will be colored red even though both rules match and the rule for the h1
selector comes later in the stylesheet.
<h1 class="my-element">Heading</h1>
.my-element {
color: red;
}
h1 {
color: blue;
}
An id
makes the CSS even more specific,
so styles applied to an ID will override those applied many other ways.
This is one reason why it is generally not a good idea to attach styles to an id
.
It can make it difficult to overwrite that style with something else.
Specificity is cumulative
As you can find out in the next lesson,
each type of selector is awarded points which indicate how specific it is,
the points for all of the selectors you have used to target an element are added together.
This means that if you target an element with a selector list such as
a.my-class.another-class[href]:hover
you get something quite hard to overwrite with other CSS.
For this reason, and to help make your CSS more reusable,
it's a good idea to keep your selectors as simple as possible.
Use specificity as a tool to get at elements when you need to,
but always consider refactoring long, specific selector lists, if you can.
Origin
The CSS that you write isn't the only CSS applied to a page. The cascade takes into account the origin of the CSS. This origin includes the browser's internal stylesheet, styles added by browser extensions or the operating system, and your authored CSS. The order of specificity of these origins, from least specific, to most specific is as follows:
- User agent base styles. These are the styles that your browser applies to HTML elements by default.
- Local user styles. These can come from the operating system level, such as a base font size, or a preference of reduced motion. They can also come from browser extensions, such as a browser extension that allows a user to write their own custom CSS for a webpage.
- Authored CSS. The CSS that you author.
- Authored
!important
. Any!important
that you add to your authored declarations. - Local user styles
!important
. Any!important
that come from the operating system level, or browser extension level CSS. - User agent
!important
. Any!important
that are defined in the default CSS, provided by the browser.
If you have an !important
rule type in the CSS you have authored
and the user has an !important
rule type in their custom CSS, whose CSS wins?
Check your understanding
Test your knowledge of cascade origins
Test your knowledge of cascade origins, consider the following style rules from various origins:
User-agent style
h1 { margin-block-start: 0.83em; }
Bootstrap
h1 { margin-block-start: 20px; }
Page Author styles
h1 { margin-block-start: 2ch; } @media (max-width: 480px) { h1 { margin-block-start: 1ch; } }
User custom style
h1 { margin-block-start: 2rem !important; }
Then, given the following HTML:
<h1>Lorem ipsum</h1>
What is the final margin-block-start
of the h1
?
!important
user custom style has the most specific origin.Importance
Not all CSS rules are calculated the same as each other, or given the same specificity as each other.
The order of importance, from least important, to most important is as follows:
- normal rule type, such as
font-size
,background
orcolor
animation
rule type!important
rule type (following the same order as origin)transition
rule type
Active animation and transition rule types have higher importance than normal rules.
In the case of transitions higher importance than !important
rule types.
This is because when an animation or transition becomes active,
its expected behaviour is to change visual state.
Using DevTools to find out why some CSS is not applying
Browser DevTools will typically show all CSS that could match an element, with those which are not being used crossed out.
If the CSS you expected to apply doesn't appear at all, then it didn't match the element. In that case you need to look elsewhere, perhaps for a typo in a class or element name or some invalid CSS.
Check your understanding
Test your knowledge of the cascade
The Cascade can be used for...