CSS Tutorial / CSS Inheritance, Specificity, and the Cascade
The cascade chooses between competing CSS declarations, while specificity compares the strength of selectors within the relevant cascade conditions. Inheritance supplies certain values from a parent when no applicable declaration determines them; these are related but different mechanisms.
Distinguish inheritance from direct declarations
Inheritance is when a child element inherits the value of its parent element. While text color and font-related properties are generally inherited, border and padding are not inherited by default. If you assume that all properties will be the same as their parent, you may end up finding unexpected borders in your paragraphs.
#main {
color: purple;
border: 1px solid purple;
}
p { color: #555; }
<main id="main"> <h1>Small Garden</h1> <p>Visitor information.</p> </main>
Assuming we only apply these two pieces, h1 will inherit the purple color from its parent main. The gray color you specify is applied to p. Just because the parent's #main is an ID selector, it does not trump the child p's direct assignment. This is because it is not a competition between two selectors applying to the same element. The border is created around main's box and is not duplicated by the borders of h1 and p respectively.
Non-inherited properties can also inherit the parent's calculated value by specifying it as border: inherit. Conversely, even if there is a declaration that applies to the element, even if it is an inherited property, that declaration is processed first. You can find out which properties are inherited and what inherit means in MDN's CSS inheritance description.
Follow the cascade decision process
Start with ordinary author CSS, such as the rules you write for this page. Before comparing declarations, verify that the selector matches, the syntax is valid, and conditions such as media queries apply. Exclude unmatched rules and invalid declarations from the comparison.
- Check the top conditions such as source, importance, and layer. Author CSS and user CSS/browser default style sources, whether !important, whether @layer is used, etc. are relevant here. If the top conditions are different, the decision is not made by comparing only the selector's scores.
- Compares selector specificity within the same conditions. Priority (specificity) is a criterion for comparing how specific a selector is. Compare ID, class family, and element family in that order.
- If the priority is the same, the declaration written later is used. In situations where there are no additional conditions such as @scope, as in the examples in this lesson, final ties are resolved in source order.
- For each property, CSS resolves the applicable declarations and then performs defaulting where necessary. Inheritable properties can obtain a parent value; other properties normally use their initial value. This does not mean that every declaration in a winning rule replaces an entire earlier rule.
The cascade is the complete CSS conflict-resolution process; selector specificity is one criterion within it. Animations, transitions, layers, and scopes introduce further rules, so the simple examples here do not represent every case. The W3C cascade sorting rules define the relationships between origin, importance, and layers. The full example below uses no animations, transitions, @layer, or @scope. The Organize CSS with Shared Styles, Nesting, and Layers demonstrates grouping rules into layers.
Compare specificity in three columns
The basic selector in this lesson can be read in three columns: number of IDs, number of classes/attributes/pseudo-classes, and number of elements/pseudo-elements. Compare from the left column, and if there is a difference, decide based on the result. Don't just memorize it as a decimal score table by simply adding ID=100, class=10, element=1. Just because there are a lot of classes doesn't mean it goes beyond the ID column.
| selector | ID | Class, attribute, pseudo-class | Element/Pseudo-element | notation |
|---|---|---|---|---|
p |
0 | 0 | 1 | 0-0-1 |
.notice |
0 | 1 | 0 | 0-1-0 |
p.notice |
0 | 1 | 1 | 0-1-1 |
[required] |
0 | 1 | 0 | 0-1-0 |
a:hover |
0 | 1 | 1 | 0-1-1 |
p::before |
0 | 0 | 2 | 0-0-2 |
#opening |
1 | 0 | 0 | 1-0-0 |
#main .notice |
1 | 1 | 0 | 1-1-0 |
p.notice and .notice have the same ID column and the same class column. There is a difference between 1 and 0 in the element column, so p.notice is high. #opening and p.notice have a difference of 1 and 0 in the first column, so #opening is high. Whitespace, relational notations such as >, +, ~ and the universal selector * do not directly increase the number of these comparisons.
p.notice { color: #087f5b; }
.notice { color: tomato; }
Under the same origin, importance, and layer conditions, p.notice has higher specificity than .notice, so its green color wins even when it appears earlier. Identical selectors have equal specificity, letting source order resolve a tie. Some functional pseudo-classes have additional specificity rules. See MDN: Specificity.
Resolve each property separately
.notice {
color: blue;
padding: 12px;
border: 1px solid #087f5b;
}
.notice {
color: tomato;
padding: 20px;
}
If only these two rules are applied to the same element, color and padding use the declaration from the latter, and border from the previous rule remains. Just because there is no border in the following rule does not mean that the entire previous rule disappears. CSS should be understood as “determining values for each property” rather than “selecting an entire rule block”.
For example, the text color may come from an ID rule, the margin may come from a later class rule, and the border may come from a previous class rule. Even when you see the strikethrough in developer tools, read the declarations one by one. Just because the color has a strikethrough does not mean that the padding of the same block is not applied.
Predict the complete example before running it
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Small Garden</title>
<style>
body { margin: 24px; font-family: sans-serif; line-height: 1.7; }
#main { color: purple; }
p { color: #555; }
.notice {
color: blue;
padding: 12px;
border: 1px solid #087f5b;
}
p.notice { color: #087f5b; }
.notice { color: tomato; padding: 20px; }
#opening { color: #1d4ed8; }
</style>
</head>
<body>
<main id="main">
<h1>Small Garden</h1>
<p id="opening" class="notice">A: We open at 9am every day.</p>
<p class="notice">B: Prepare a water bottle and comfortable shoes.</p>
<p>C: Please inquire at the information desk.</p>
</main>
</body>
</html>
Predict the colors of A·B·C and the notice margin before opening it in your browser. If you save the entire code as index.html and open it, you will get the following result. The body font and line height are auxiliary settings for easier viewing.
| object and properties | final result | Reason for decision |
|---|---|---|
| color of h1 | Purple | Inherits the color of main. There are no other color declarations in h1. |
| color of A | Blue #1d4ed8 | #opening has higher specificity than p.notice, .notice, p applied to the same A. |
| color of B | Green #087f5b | p.notice has higher specificity than later .notices. |
| color of C | Gray #555 | It uses a direct value for p and does not inherit the parent's purple color. |
| padding of A·B | 20px | The two .notice declarations have the same specificity, so the latter padding wins. |
| border of A·B | 1px green solid line | Since there is no border declaration in the latter rule, the preceding valid declaration remains. |
When checked in Computed, the color of A can be displayed as rgb(29, 78, 216), the color of B can be displayed as rgb(8, 127, 91), and the color of C can be displayed as rgb(85, 85, 85). Even if the color notation is different, it indicates the same value. Check that the padding is 20px in each direction and that the border thickness and line shape are the same.
Compare !important and inline styles
!important is a notation that changes the importance of a declaration. It's not a function that adds a large number to the three columns of the selector. From the same author's source, important declarations take precedence over regular declarations, so adding the rule below to the end of the entire example will change the color of both A and B to tomato. The plain color declaration in ID also does not take precedence over this important declaration.
.notice { color: tomato !important; }
This result does not mean that important is always stronger than all styles. User important styles, values during transitions, etc. follow a separate order. Even among important declarations, you must first check the source and layer. In this exercise, observe important and then delete the rule you added. Usually, it is better for maintenance to organize the selection range and structure first.
<p class="notice" style="color: purple;">B: Information on what to prepare</p>
In the original example where the important rule was deleted, if you put an inline color in B as above, it will take precedence over the regular style sheet rules and B will become purple. Inline styles are treated separately from the three default selector columns in the table above. Again, putting important in the general class rule allows it to take precedence over the regular color inline. Therefore, “if it is inline, it is unconditionally the strongest” is also an explanation without conditions.
Practice diagnosing conflicts
- In the original full example, move the
p.noticerule to the bottom. Make sure B is still green and A retains the blue color of its ID. In states with high specificity, they will not be overturned simply by changing their order. - Next, change only the p.notice selector to
.noticeand place it at the bottom. The color of B uses the green specified by the last .notice. Since we have the same selector, order is now the decision criterion. After confirmation, restore the original. - It only removes
id="opening"from A. See if A becomes the same green as B. Even though the ID of the parent main remains the same, it does not beat the green color assigned directly to A. After confirmation, your ID will be restored. - In separate steps, apply the above important and inline examples one by one and compare them. Instead of leaving the previous practice rules behind, go back to the original and add the following conditions:
If the result differs from your expectation, Inspect CSS with DevTools: Styles and Computed. Select the correct element, find declarations for the property, compare their importance, selectors, and order, and then inspect the final value. Adding IDs or !important without finding the cause may change the color now while making later edits harder.










