CSS Cascade: Specificity, Inheritance and Style Resolution

How Blink turns a pile of stylesheets into one computed style per element. Specificity is a packed 24-bit integer whose fields saturate rather than carry, !important inverts the origin order instead of adding to it, and a stylesheet that arrives after <body> stops blocking paint while still blocking scripts. Every behaviour here is read from Chromium 154 source, not from the spec's prose.

Launch Simulator →

What you'll explore

  1. 01

    Specificity

    Blink does not weigh selectors, it packs them. Each simple selector adds into one of three 8-bit fields of a single unsigned integer, and each field clamps at its maximum instead of carrying into the one above it. That is why a selector's specificity can be compared with a single integer comparison, and why no quantity of classes can ever reach the ID field.

  2. 02

    Inheritance

    An inherited property is not copied by a per-property loop at resolve time. The resolver seeds an element's style by constructing a builder from the parent's computed style, so inherited values are already in place before any declaration is applied. A separate fast path exists for properties that can be updated on their own without a full re-resolve.

  3. 03

    Cascade origin and !important

    Origin is a small bitfield: user-agent, user, author, animation, transition. For !important declarations the low four bits are inverted, which reverses the ordering rather than shifting it. The consequence surprises most engineers: a user-agent !important outranks an author !important, which is what makes accessibility and print defaults unoverridable by page CSS.

  4. 04

    Computed values

    Resolving style runs the whole cascade for one element and produces a ComputedStyle. Reading it back through getComputedStyle() is a different operation again: for layout-dependent properties the CSSOM returns the resolved value, which may require layout to have run, rather than the value the cascade computed.

  5. 05

    Render-blocking CSS

    A stylesheet blocks first paint only while no <body> element exists yet. Once the parser has opened <body>, a newly discovered sheet is no longer render-blocking — but it is still counted as script-blocking and parser-blocking, so it delays script execution instead of paint. A late stylesheet is not free; it trades a blank screen for a stall somewhere else.

Validated against Chromium Blink — core/css style resolution chromium-154.0.8037.57 — third_party/blink/renderer/core/css/css_selector.cc and friends. Every simulated behavior cites a real source function, and a server-side correlation engine computes how each layer's state cascades into the next. See the methodology →

This module is part of zerohop Pro — it unlocks alongside the full kata library, progress tracking, and weak-area analysis.