DEV Community

Cover image for The "C" in CSS: A Guide to Cascade, Specificity, and Inheritance
Akash for MechCloud Academy

Posted on

The "C" in CSS: A Guide to Cascade, Specificity, and Inheritance

Have you ever written a CSS rule that you were sure was correct, only to find it wasn't being applied? You check the syntax, you check the class name, and everything seems right, but another style is taking precedence. This common frustration is almost always a result of not fully understanding the three fundamental principles that govern CSS: Inheritance, Specificity, and the Cascade.

These three concepts are the "rules of the game." They dictate which styles apply to which elements and how conflicts between competing styles are resolved. Mastering them will transform you from someone who just writes CSS into someone who truly understands it, allowing you to debug with precision and write more predictable, maintainable code.

Let’s break down these foundational pillars one by one.


Part 1: Inheritance - The Family Tree of Styles

Inheritance is the most intuitive of the three concepts. It describes how some CSS properties, when applied to a parent element, are passed down—or inherited—by their child elements.

Think of it like a family tree. Children inherit certain traits from their parents. In the same way, a <p> tag inside a <div> will inherit certain styles from that <div>.

Which properties are inherited?

Not all properties are created equal. Inheritance primarily applies to properties related to text. This makes sense; you typically want your entire document to share a consistent font, size, and color unless specified otherwise.

  • Common Inherited Properties: color, font-family, font-size, font-weight, line-height, text-align, list-style.
  • Common Non-Inherited Properties: background-color, border, padding, margin, width, height. These properties relate to the element's box model and layout, and it would cause chaos if every child element inherited its parent's border or padding.

A Practical Example:

Let's set a default font and color on the <body> element.

HTML:

<body>
  <h1>This is a heading</h1>
  <p>This is a paragraph with a <strong>strong</strong> tag inside.</p>
</body>
Enter fullscreen mode Exit fullscreen mode

CSS:

body {
  font-family: 'Helvetica', sans-serif;
  color: #333; /* A dark grey */
}
Enter fullscreen mode Exit fullscreen mode

Because of inheritance:

  • The <h1> and <p> tags will inherit the Helvetica font from the <body>.
  • They will also inherit the dark grey text color.
  • Even the <strong> tag, a child of the <p>, will inherit these properties. You don't need to style them individually.

Forcing Inheritance with the inherit Keyword
What if you want a property that isn't normally inherited to take on its parent's value? You can use the inherit keyword. For example, you could make a child element's border color the same as its parent's text color.

.parent {
  color: blue;
  border: 2px solid black;
}

.child {
  /* This will make the border blue, not black */
  border-color: inherit; 
}
Enter fullscreen mode Exit fullscreen mode

Inheritance is powerful, but it's only the first step. What happens when you explicitly define a different style on a child element? That's where the Cascade and Specificity come in.


Part 2: The Cascade - Order of Operations

The "C" in CSS literally stands for "Cascading." The cascade is a formal algorithm that defines how to combine property values from different sources. It answers the question: "When multiple rules apply to the same element, which one wins?"

The cascade follows a specific order of importance. If a property is declared in multiple places, the winner is chosen from the list below, in descending order of power:

  1. Importance (!important): Any style with !important appended to it will almost always win. This is a powerful override that should be used with extreme caution.
  2. Origin: Where the stylesheet comes from. There are three main origins:

    • Author Stylesheets: This is the CSS you write for your website.
    • User Stylesheets: Some browsers allow users to apply their own custom stylesheets (e.g., for accessibility reasons).
    • User-Agent Stylesheets: These are the browser's default styles (e.g., links are blue and underlined, <h1> tags are large and bold).

    The normal cascade order is: Author > User > User-Agent. Your styles will override the browser's default styles.

  3. Specificity: If two rules have the same origin and importance, the more specific selector wins. We will cover this in detail in the next section.

  4. Source Order: If all else is equal (same importance, origin, and specificity), the last rule declared in the code wins.

Example of Source Order:

p {
  color: blue;
}

/* ... more CSS ... */

p {
  color: red; /* This one wins! */
}
Enter fullscreen mode Exit fullscreen mode

Because both rules target the p element (identical specificity), the one that comes last in the stylesheet is applied.

The !important Exception
!important flips the priority of stylesheet origins. When !important is used, the order becomes: User > Author > User-Agent. This ensures that a user's accessibility needs (e.g., "make all fonts huge!") can override the website's design.

Use !important sparingly. It breaks the natural flow of the cascade and makes debugging much harder. It's best reserved for overriding styles from third-party libraries or for highly specific utility classes.


Part 3: Specificity - The Tie-Breaker

Specificity is the most complex—and most critical—concept of the three. It is the algorithm the browser uses to calculate the "weight" or "power" of a CSS selector. When multiple rules from the same origin target the same element, the rule with the highest specificity wins, regardless of its source order.

Think of it as a scoring system. The higher the score, the more specific the selector.

The Specificity Hierarchy

Specificity is typically calculated by counting the number of selectors in four categories. We can visualize this as a four-digit number: (Inline, IDs, Classes, Elements).

  1. Inline Styles (Score: 1,0,0,0)

    • Styles applied directly to an element using the style attribute (e.g., <p style="color: red;">). This has the highest specificity, so it's very difficult to override with external CSS. Avoid this for general styling.
  2. IDs (Score: 0,1,0,0)

    • Selectors that use an ID (e.g., #main-content). IDs are meant to be unique, so they carry a lot of weight.
  3. Classes, Pseudo-classes, and Attribute Selectors (Score: 0,0,1,0)

    • This is the most versatile category. It includes:
      • Classes (e.g., .intro, .btn-primary).
      • Pseudo-classes (e.g., :hover, :focus, :nth-child()).
      • Attribute selectors (e.g., [type="submit"]).
  4. Elements and Pseudo-elements (Score: 0,0,0,1)

    • Selectors for element types (e.g., p, h1, div).
    • Pseudo-elements (e.g., ::before, ::after).

Important Note: The universal selector (*) and combinators (+, ~, >) have no specificity value.

How to Compare Specificity

When comparing two selectors, you compare their scores from left to right (from IDs down to Elements).

  • A selector with 1 ID will always beat a selector with any number of classes. For example, a specificity of (0,1,0,0) beats (0,0,20,0).
  • A selector with 1 class will always beat a selector with any number of elements. (0,0,1,0) beats (0,0,0,15).

Let's see it in action:

HTML:

<div id="sidebar">
  <p class="promo highlight">Special Offer!</p>
</div>
Enter fullscreen mode Exit fullscreen mode

CSS with Specificity Scores:

/* Specificity: (0,0,0,1) */
p {
  color: black;
}

/* Specificity: (0,0,1,0) */
.promo {
  color: blue;
}

/* Specificity: (0,0,2,0) */
.promo.highlight {
  color: green;
}

/* Specificity: (0,1,0,1) */
#sidebar p {
  color: red;
}
Enter fullscreen mode Exit fullscreen mode

Result: The paragraph text will be red. The rule #sidebar p wins because its specificity score of (0,1,0,1) beats all the others. It has one ID, which is more powerful than any number of classes.

Putting It All Together

The browser follows this process to style an element:

  1. Gather all the rules that match the element from all sources.
  2. Sort the rules based on their origin and importance (with !important rules getting top priority).
  3. For rules from the same origin, calculate the specificity of each selector. The rule with the highest specificity wins.
  4. If any rules have the exact same specificity, use source order: the last one declared in the code wins.

Conclusion: Writing Better CSS

Understanding these three pillars empowers you to write CSS with confidence.

  • Leverage Inheritance for global styles like fonts and colors.
  • Respect the Cascade by structuring your CSS logically.
  • Master Specificity to control your styles precisely.

Final Tips for Success:

  • Keep Specificity Low: Use the least specific selector that gets the job done. This makes your styles easier to override later. Prefer classes over IDs for styling.
  • Avoid !important: Only use it as a last resort.
  • Use Your Browser's DevTools: The "Inspect Element" tool is your best friend. It shows you exactly which styles are being applied to an element and which ones are being overridden, often telling you why. This is the fastest way to debug CSS conflicts.

Top comments (0)