We style our websites using CSS, which stands for Cascading Style Sheets.
But what does Cascading really mean?
The CSS Cascade is one of the most powerful parts of CSS. But it can also be very frustrating, if not well understood. Anyone who’s worked on a large enough website has complained "Why won’t this CSS property work?!" And we’ve all been tempted to throw an !important
to strong-arm things into place.
To save ourselves from future angst, let’s take a step back and learn this thing for real.
Every time we write a CSS declaration (or rule), it will enter the CSS Cascade, which will determine whether or not it will end up as the final style. The further down the cascade a declaration falls, the less likely it will end up as the final style.
Let’s take a look at the different tiers of the Cascade.
The first tier of the Cascade looks at the type of rule we’re looking at.
There are four basic types of rules:
!important
to the end of our declaration, it jumps to this level of the Cascade. Ideally, you reserve this level for Hail Marys, which are needed to override styles from third-party libraries.As you can see, this top tier is mostly reserved to ensure our elements animate properly, and to help out desperate developers (!important
).
Let’s look at how this rule plays out:
Which of these two rules would win?
p {
color: sandybrown;
}
p {
color: orchid !important;
}
!important
declarations fall on the second level, while normal declarations fall on the fourth level.If two rules are tied on one tier of the Cascade, the fight goes on to another round, looking for a difference on the next tier.
The second tier of the Cascade looks at where the rule was defined.
There are three places where a rule can be defined:
<button>
s have default styles.Fight time! Which of these two rules would win?
p {
color: sandybrown;
}
p {
color: orchid;
}
The third tier of the Cascade looks at the Specificity of a rule.
There are five levels of selectors:
style
HTML property are the most specific@layers one, two; // defining our layers
@layer one {
body { color: red; }
}
@layer two {
body { color: green; }
}
layer two
is defined after layer one. Unlayered styles will take precendence, though, to help with backwards compatibility.When we create a CSS declaration, we can target specific elements using selectors.
id
, using the syntax #id
class
, using the syntax .class
[checked]
and [href="https://wattenberger.com"]
:hover
and :first-of-type
type
:before
and :selection
Fight time! Which of these two rules would win?
<p style="color: sandybrown">...</p>
p {
color: orchid;
}
What about these two rules?
.paragraph {
color: sandybrown;
}
#paragraph {
color: orchid;
}
One thing to note about levels on this tier is that the number of hits on the highest-reached level matter.
.paragraph:first-of-type {
color: sandybrown;
}
p.paragraph {
color: orchid;
}
Additionally, on this tier of the Cascade, ties can be broken within this tier. This means that, if two rules have the same number of hits on their highest level, one can win by having a hit on the next level down.
p#paragraph {
color: sandybrown;
}
#paragraph.paragraph {
color: orchid;
}
And lastly, we descend to the fourth, and final, tier of the Cascade, which looks at the order that the rules were defined in.
Rules that are defined later in linked stylesheets or <style>
tags will win, given that everything else in the Cascade is the same.
p {
color: sandybrown;
color: orchid;
}
p {
color: sandybrown;
color: orchid;
}
Hopefully, this helps clear up some confusion about styles are prioritized!
Next time you find yourself reaching for the big, red !important
button, take a step back and look at where competing styles fall on the Cascading waterfall.