Cascade and Inheritance
At some point, you will find yourself in a situation where multiple CSS rules have selectors targeting the same element. In such cases, a dilemma arises: which CSS rule "wins" and ends up being the one applied to the element in the end.
This is controlled by a mechanism called the "Cascade," but it is also related to inheritance — elements will inherit rules from parents, but not from other elements.
In this chapter, we will clarify what the CSS cascade is, specificity and importance, and how CSS properties inherit different values.
The final style for an element can be specified in many different places, which can interact in complex ways. This complex interaction makes CSS very powerful, but sometimes confusing and hard to debug.
I will try to clarify some of this complexity, and if you don't understand immediately, that's normal, because I'm trying to help you understand one of the most challenging parts of CSS theory.
Cascade
CSS stands for "Cascading Style Sheets." This means that, at the most basic level, the order of CSS rules matters — although things are much more complex than that.
Multiple sets of rules can apply to a single element. To decide the order in which styles should be applied, the standard defines the cascade. The rule selection process is as follows:
- Find all declarations that apply to a particular element;
- Sort them by origin and level of importance;
- Declarations with the same importance and the same origin are ordered by specificity;
- If they have the same origin, importance, and specificity, they are applied in the order they were declared.
Which selectors in the cascade "win" depends on three factors listed in order of weight, with the note that the first can override the last:
- Importance
- Specificity
- Order
Stylesheet Origin and Importance Level
From the origin perspective, there are three types of stylesheets (in ascending order of priority):
- User agent stylesheets — predefined browser styles. If you test a page without any defined styles, you will notice that some default styles are still applied to elements (e.g., links are blue). Since there is no universally accepted browser standard, it is sometimes recommended to use a reset stylesheet to start from the same base styles in any browser.
- Author stylesheets — styles defined by the web page author (included in the page with link, style, or inline attribute style="...").
- User stylesheets — some browsers allow users to override page styles by applying stylesheets on top of the ones defined by the page authors.
Regarding importance, there are two levels:
- Important rules. Important rules are marked with the !important declaration and take precedence over normal rules.
- Normal rules.
Depending on origin and importance, the order of applying rules is (in ascending order of priority):
- Browser-level rules (user-agent stylesheets);
- Normal importance rules from user stylesheets;
- Normal importance rules from author stylesheets;
- Important rules from author stylesheets;
- Important rules from user stylesheets.
Importance
In CSS syntax, there is an element that can be used to ensure that a particular declaration will always win: !important.
☞ The !important value should only be used when there is no
other solution, because it can unnecessarily complicate stylesheets and make them very hard to modify and
maintain.
Specificity
Specificity is a way to measure the "weight" of a selector.
As mentioned above, if two sets of rules have the same origin and the same importance, ordering is done according to specificity.
Specificity can be calculated as follows:
- Count the ID selectors (
#IDName) in the rule. - Count the class selectors (
.ClassName) and the number of pseudo-classes (:hover). The declaration with the highest total number of such selectors will have higher specificity. If there is still a tie, proceed to the last step. - Count the element selectors (
div,p,h1, etc.) and pseudo-elements (::first-letter).
The declaration with the highest score is the one that will be applied, because it has the highest specificity.
If there is still a tie between declarations, the difference will be made by the order in which they were declared.
To simplify the process of calculating a selector's specificity, you can use a four-value method: thousands, hundreds, tens, units (four unique digits in four columns).
- Thousands – can be 0 (declarations are in a
styletag or external file) or 1 (declarations are inline, via the element'sstyleattribute); - Hundreds – one point for each ID in the general selector;
- Tens – one point for each class, attribute selector, or pseudo-class in the general selector;
- Units – one point for each element selector or pseudo-element in the general selector.
To better understand, let's look at the table below:
| Selector | Thousands | Hundreds | Tens | Units | Total |
|---|---|---|---|---|---|
h1 |
0 | 0 | 0 | 1 | 0001 |
h1 + p::first-letter |
0 | 0 | 0 | 3 | 0003 |
li > a[href*="en-US"] > .warning |
0 | 0 | 2 | 2 | 0022 |
#identifier |
0 | 1 | 0 | 0 | 0100 |
| No selector, inline CSS | 1 | 0 | 0 | 0 | 1000 |
Source Order
As mentioned before, if multiple competing selectors have the same importance and specificity, the third factor that comes into play to determine the winning rule is source order — meaning later rules override earlier rules.
☞ One thing to keep in mind when thinking about cascade theory and rules overriding other rules is that all of this happens at the property level — properties override other properties, not rules completely replacing other rules.
When multiple CSS rules target the same element, initially all rules are applied. Only after evaluating conflicts is it determined which rules win and will be applied finally.
Inheritance
CSS inheritance is the last piece we need to explore to understand what style is applied to an element. The idea is that some property values applied to an element will be inherited by its children, while others will not.
For example, it makes sense for font and color to be inherited, as the author can set a font for the entire site by applying it to the html element, and it will only be overridden where necessary.
It would be inefficient to have to set the font separately for each element on the site.
Another logical example: properties like margin, padding, border, and
background-image are not inherited. If they were automatically inherited, they would need to be
manually removed or modified for each child element.
The full list of inherited properties can be found in the CSS documentation.
Controlling Inheritance
CSS provides four values to control inheritance:
- inherit — Sets the property value of an element to be identical to that of its parent element.
- initial — Sets the property value according to the browser's default stylesheet. If the property is naturally inherited, it behaves like inherit.
- unset — Resets the property to its natural value: if it is normally inherited, it acts as inherit, otherwise as initial.
- revert — Resets the property to the value it would have had before being overridden.
Among these, inherit is the most useful when we want an element to explicitly inherit a value from its parent.
Resetting All Property Values
Using the shorthand property all, any of the discussed inheritance values can be applied to almost all properties simultaneously. It is a convenient way to return to a "zero moment" before adding new styles.
all: initial; all: inherit; all: unset; all: revert;
In the following exercise, try writing a single rule that overrides the color and background-color properties applied by default to links.
