|$ curl https://forge-ai.dev/api/markdown?path=docs/css/cascade
$cat docs/cascade-&-specificity.md
updated Yesterday·12 min read·published

Cascade & Specificity

CSSCascadeFundamentalsBeginner
What is the Cascade?

The cascade is the algorithm browsers use to resolve conflicting CSS declarations. When two or more rules apply to the same element, the cascade determines which property value takes effect. Understanding this algorithm is essential for writing predictable, maintainable stylesheets.

The word "cascading" reflects how styles flow from multiple sources — user agent defaults, user stylesheets, and author stylesheets — with later sources overriding earlier ones. The cascade considers six factors in order of importance.

1Origin & Importance
2Context (inline vs scoped)
3Style attribute (inline styles)
4Specificity
5Cascade layers (@layer)
6Source order (last wins)
cascade-basics.css
CSS
1/* The cascade resolves conflicts step-by-step.
2 Only one value wins per property per element. */
3
4/* Both rules apply to <p class="highlight">Hello</p> */
5p { color: #A0A0A0; } /* specificity: 0,0,0,1 */
6.highlight { color: #00FF41; } /* specificity: 0,0,1,0 → wins */
7
8/* The cascade determines that .highlight is more specific */
Source Order

When specificity and origin are equal, source order decides: the last declaration in the stylesheet wins. This is the simplest tiebreaker and a common source of confusion.

Source order applies within each stylesheet, across multiple stylesheets (later <link> tags override earlier ones), and within a single declaration block (later properties override earlier ones for the same property).

source-order.css
CSS
1/* Source order: last identical-specificity rule wins */
2.button { color: blue; }
3.button { color: red; } /* wins — comes last */
4
5/* Multiple stylesheets */
6/* styles.css (loaded first) */
7.button { background: blue; }
8
9/* theme.css (loaded second — overrides) */
10.button { background: green; } /* wins */
11
12/* Inside a declaration block — later override earlier */
13.element {
14 color: red;
15 color: blue; /* wins — also acts as a fallback for older browsers */
16}

info

The fallback pattern — declaring the same property twice with different values — is a useful technique. Older browsers that don't understand the second value will use the first. Modern browsers apply the second value.
Specificity Calculation

Specificity is calculated as a four-column weight: (inline, IDs, classes, elements). Each selector type contributes to one column, and the comparison is made left-to-right — a single ID beats any number of classes.

SelectorInlineIDClassElementTotal
p00010,0,0,1
.card00100,0,1,0
#header .nav a01110,1,1,1
ul li:first-child00120,0,1,2
style="color: red;"10001,0,0,0
#app .sidebar .nav a:hover01310,1,3,1
.card.highlighted[data-active]00300,0,3,0
specificity-calc.css
CSS
1/* Specificity comparison examples */
2
3/* 0,0,0,1 vs 0,0,1,0 — class wins */
4p { color: #808080; }
5.text { color: #00FF41; } /* wins */
6
7/* 0,1,0,0 vs 0,0,3,0 — ID wins over three classes */
8#title { color: #FFB000; } /* wins */
9.page .header .title { color: red; }
10
11/* 0,1,1,0 vs 0,1,0,3 — class tips the scale */
12#nav .link { color: blue; } /* wins (0,1,1,0) */
13#nav a span strong { color: red; } /* loses (0,1,0,3) */
14
15/* Compound selectors add weight */
16a[href].external:hover {
17 /* 0,0,3,0 — attribute + class + pseudo-class */
18}
preview
The !important Keyword

Adding !important to a declaration elevates its priority above all normal declarations, regardless of specificity. It is a nuclear option that breaks the cascade and should be used as a last resort.

When two declarations both have !important, the cascade falls back to specificity and source order to resolve the conflict. So !important is not absolute — it just changes the game from "normal" to "important" contexts.

important.css
CSS
1/* Without !important */
2#header .title { color: red; } /* 0,1,1,0 wins */
3.title { color: blue; } /* 0,0,1,0 loses */
4
5/* With !important — the tables turn */
6.title { color: blue !important; } /* wins over normal IDs */
7#header .title { color: red; } /* loses — no !important */
8
9/* Two !important declarations — specificity kicks in */
10.title { color: blue !important; } /* 0,0,1,0 — loses */
11#header .title { color: red !important; } /* 0,1,1,0 — wins */
12
13/* Acceptable uses for !important */
14/* 1. Utility classes (Tailwind style) */
15.hidden { display: none !important; }
16
17/* 2. Debug overrides */
18.debug-outline * { outline: 1px solid red !important; }
19
20/* 3. User-defined overrides in user stylesheets */
21body { font-size: 18px !important; }

warning

Never use !important in application component styles. It creates specificity arms races that are impossible to maintain. The only acceptable uses are utility classes, debugging, and user-agent/user stylesheets.
Origin & Importance

CSS has three origins: the browser's user-agent stylesheet, the author's stylesheet (your CSS), and the user's stylesheet (browser preferences). Each origin can have normal and important declarations. The browser resolves them in a strict priority order.

PriorityOriginImportance
1 (highest)User agent!important
2User!important
3Author!important
4AuthorNormal
5UserNormal
6 (lowest)User agentNormal

This means user stylesheets with !important can override author styles — a feature designed for accessibility. Users with visual impairments can force larger fonts or high-contrast colors via their browser settings.

📝

note

The @layer at-rule adds another dimension to origin priority. Styles in later layers override earlier layers, and unlayered styles override layered styles. This gives authors fine-grained control over cascade order without relying on specificity or source order games.
Inheritance vs Cascade

Inheritance and the cascade are often confused but serve different purposes. Inheritance passes property values from parent to child elements automatically. The cascade resolves conflicts between declarations targeting the same element.

The cascade always wins over inheritance. If a parent has color: red (inherited by child) but a direct selector targets the child with color: blue, the child will be blue because the cascade applied the declaration directly to the child.

inheritance-vs-cascade.css
CSS
1/* Inheritance vs Cascade example */
2
3body {
4 color: #E0E0E0; /* inherited by all text children */
5 font-family: system-ui; /* inherited */
6}
7
8/* The cascade overrides inheritance for these elements */
9p { color: #A0A0A0; } /* <p> uses this, not body's #E0E0E0 */
10article { color: #808080; } /* <article> uses this instead */
11
12/* But nested children inherit from their parent's cascaded value */
13/* <p> inside <article> inherits #808080 from article */
14
15/* Cascade keywords control inheritance behavior */
16.force-inherit {
17 border: inherit; /* forces inheritance of border (normally not inherited) */
18}
19
20.reset-all {
21 all: initial; /* resets every property to CSS spec default */
22}
preview
Cascade Layers (@layer)

Cascade layers give authors explicit control over the cascade order, bypassing specificity and source order entirely. Layers are defined with the @layer at-rule, and styles in later layers override earlier layers regardless of specificity.

cascade-layers.css
CSS
1/* Define layer order — first defined = lowest priority */
2@layer reset, base, components, utilities;
3
4/* Styles in reset layer */
5@layer reset {
6 * { box-sizing: border-box; margin: 0; }
7 h1, h2, h3 { font-size: 1rem; font-weight: 400; }
8}
9
10/* Styles in base layer */
11@layer base {
12 body { font-family: system-ui; color: #E0E0E0; }
13 h1 { font-size: 2rem; font-weight: 700; } /* beats reset's h1 */
14}
15
16/* Styles in components layer */
17@layer components {
18 .card {
19 background: #0D0D0D;
20 padding: 24px;
21 border-radius: 8px;
22 }
23}
24
25/* Unlayered styles — highest priority (beat all layers) */
26.fix-override {
27 background: #1A1A2E !important;
28}

best practice

Use cascade layers in large projects to establish a clear ordering: @layer reset, base, components, utilities. This eliminates the need to micromanage specificity across your codebase. Component styles naturally override base styles, and utilities always win.
$Blueprint — Engineering Documentation·Section ID: CSS-03·Revision: 1.0