Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 6

Understanding the CSS Cascade: Origins, Specificity, and Inheritance

Recommended resources

Hello! Welcome to the first lesson in our module on CSS fundamentals.

In our previous module, we concluded our journey into HTML by examining the sophisticated parsing algorithm the browser uses to convert raw markup into a structured DOM tree. Now, we shift our focus to the "Style" in Cascading Style Sheets. We'll explore how the browser takes that DOM tree and applies visual styles to it.

Our goal today is to master the foundational rules of CSS. As an engineer, you can think of this as learning the core "execution model" of the styling engine. We will explain the CSS cascade, including the order of origin, specificity calculation, and inheritance rules.

We'll tackle this in two main parts:

  1. The Cascade: A conflict-resolution algorithm that decides which style rule wins when multiple rules apply to the same element.
  2. Inheritance: The mechanism that passes down property values from parent to child elements, and how to control it.

The CSS Cascade: An Algorithm for Conflict Resolution

When you write CSS, you'll often have multiple rules that could apply to the same element. The browser needs a deterministic way to decide which one takes precedence. This is the job of the cascade.

Think of it as a multi-step algorithm that filters and sorts declarations to find a single "winning" value for each property on each element.

This diagram gives a high-level overview of the steps involved. We'll walk through each one.

CSS Cascade Order Diagram
This diagram from Bramus Van Damme illustrates the sequential steps the browser takes to resolve style conflicts. The process stops as soon as a winner is found at a given step.

To begin, let's get a conceptual overview of this process.

The CSS Cascade, a deep dive | Bramus Van Damme | CSS Day 2022

This first segment from a talk by CSS expert Bramus Van Damme introduces the cascade as a multi-step algorithm for resolving conflicts between competing style declarations.

Watch from 02:49 to 05:42. Focus on understanding the cascade not as a vague concept, but as a sequential process with distinct steps. The waterfall analogy helps visualize why it's called a 'cascade'—the process stops as soon as a winner is found at any step.

Now, let's dive into the details of the most important steps in that algorithm.


The Steps of the Cascade

1. Origin and Importance

The very first check the browser makes is where a style rule comes from (its origin) and whether it's marked as important. There are three main origins:

  • User-Agent Stylesheet: The browser's built-in default styles (e.g., links are blue, <h1> is large and bold).
  • User Stylesheet: Custom styles a user might apply for accessibility or preference (e.g., to increase default font sizes).
  • Author Stylesheet: The CSS you, the developer, write for your website.

The !important flag can be added to a declaration (e.g., color: red !important;) to increase its weight.

The following video segment explains this crucial first step, including a surprising twist in how !important works.

The CSS Cascade, a deep dive | Bramus Van Damme | CSS Day 2022

The first and most powerful step in the cascade is 'Origin and Importance'. This determines which stylesheet—the browser's, the user's, or yours—gets priority. This segment explains this hierarchy and the special role of !important.

Watch from 05:42 to 11:33. Pay close attention to the list of eight origins. Notice how the normal origins are stacked (User Agent < User < Author) and how !important flips and reverses this order. This explains why !important user styles can override !important author styles—a critical detail for accessibility.

To summarize the precedence order (from lowest to highest):

Precedence Origin Importance
1 User-agent Normal
2 User Normal
3 Author Normal
4 Author !important
5 User !important
6 User-agent !important

Note: CSS animations and transitions also fit into this hierarchy, but the core origins are our focus here.

The key insight is that for normal styles, Author > User > User-Agent. But for important styles, the order is inverted: User-Agent !important > User !important > Author !important. This ensures that a user's accessibility needs (like a large font size set with !important) can override a website's design.

2. Specificity

If declarations have the same origin and importance (e.g., two rules in your author stylesheet), the browser uses specificity as a tie-breaker. Specificity is a measure of how specific a selector is.

This is not a simple numeric score; it's a three-component vector, often represented as (A, B, C):

  • A (IDs): Count the number of ID selectors (e.g., #my-id).
  • B (Classes, Attributes, Pseudo-classes): Count the number of class selectors (.my-class), attribute selectors ([type="text"]), and pseudo-classes (:hover).
  • C (Elements, Pseudo-elements): Count the number of element selectors (div, p) and pseudo-elements (::before).

When comparing two selectors, you compare the 'A' values first. If they're equal, you compare 'B'. If they're also equal, you compare 'C'. A selector with (0, 1, 0) specificity (a single class) is more specific than a selector with (0, 0, 11) specificity (eleven elements). This is a common point of confusion; it's not a base-10 calculation.

The following segment explains this calculation in detail, along with how modern pseudo-classes like :is() and :where() affect it.

The CSS Cascade, a deep dive | Bramus Van Damme | CSS Day 2022

When declarations have the same origin and importance, the browser uses 'Specificity' to decide. This is a formal calculation, not a vague weighting. This segment provides a rigorous breakdown of how specificity is calculated.

Watch from 11:33 to 22:22. The key points are: The concept of inline styles (style attribute) winning over rules in stylesheets (11:33-12:43). An inline style can be thought of as having a specificity of (1, 0, 0, 0) - higher than any ID. The (A, B, C) triad calculation for specificity. Understand that you compare 'A' values first, then 'B', then 'C'. The special, and very useful, behavior of :where(), which has a specificity of zero.

3. Order of Appearance

If two declarations have the same origin, importance, and specificity, the cascade has one final, simple rule.

The CSS Cascade, a deep dive | Bramus Van Damme | CSS Day 2022

If all else is equal, the cascade has one final, simple rule: 'Order of Appearance'.

Watch from 22:22 to 23:11. The takeaway is simple: the last declaration defined in the source code wins.

This is why the order of your <link> tags or CSS rules in a file matters.


Defaulting and Inheritance

The cascade is for resolving conflicts. But what happens if no CSS rule you've written declares a value for a property on an element, like the color of a <li> inside a <div>? This is where defaulting comes in.

To formalize this, let's look at the official processing model.

CSS property value processing

The browser follows a formal process to assign a value to every property on every element. This MDN article introduces the key phases: Filtering, Cascading, and Defaulting. This framework connects the cascade algorithm to the concept of inheritance.

Read the sections 'Processing overview' and 'Processing stages'. Focus on: Cascading: The process we just studied, which results in a 'cascaded value'. Defaulting: What happens when there is no cascaded value. This involves either inheritance or using an initial value. The formal definitions of 'Cascaded value' vs. 'Specified value'. The specified value is the final value after the defaulting process.

As the article states, defaulting has two paths:

  1. Inheritance: For properties that are inherited by default (like color, font-size, font-family), the element takes the computed value of its parent.
  2. Initial Value: For properties that are not inherited (like border, padding, margin), the element uses the property's specified initial value.

We have four keywords to explicitly control this defaulting behavior.

Do You Really Understand CSS Inheritance?

Let's explore the 'Defaulting' process in detail. This video clearly explains the keywords you can use to explicitly control whether a property inherits from its parent or resets to a default value.

Watch from 01:05 to 10:40. Pay attention to the subtle but important distinctions between: initial: The property's default as defined in the CSS specification (often not what you expect). inherit: Forces the element to take the computed value from its parent. revert: Resets the property to the value it would have from the user-agent stylesheet. unset: Behaves like inherit for inherited properties, and initial for non-inherited ones.

Here is a summary of these powerful keywords:

Keyword Description
inherit The element explicitly inherits the value of the property from its direct parent.
initial The element uses the property's default value as defined in the CSS specification.
unset A context-aware keyword. It acts as inherit if the property is naturally inherited, and as initial if it is not.
revert Reverts the property to the value established by the previous origin in the cascade. For you as an author, this usually means reverting to the user-agent (browser) style.

Understanding these keywords is essential for writing clean, predictable CSS resets and component styles.


Conclusion

Today, you've learned the fundamental rules that govern how styles are applied in a browser. This is the bedrock upon which all other CSS concepts are built.

Key Takeaways:

  • The cascade is a formal, multi-step algorithm (Origin & Importance -> Specificity -> Order of Appearance) that browsers use to resolve conflicting style declarations.
  • Specificity is a three-part vector (A, B, C), not a single number, and is a primary tie-breaker within the same origin.
  • When no declaration is found by the cascade, the browser engages in defaulting.
  • Defaulting means either inheriting a value from a parent (for properties like color) or using the property's initial value (for properties like margin).
  • Keywords like inherit, initial, unset, and revert provide you with explicit, granular control over this defaulting and inheritance behavior.

What's Next?

Now that we understand how the browser decides which styles to apply, our next lesson will focus on how those styles affect an element's space on the page. We will explore the CSS box model, explaining its components (content, padding, border, margin) and the critical role of the box-sizing property.