CSSOM
The CSS Object Model: the parsed stylesheets as a tree of rules the engine matches against the DOM and scripts can read.
in practicedocument.styleSheets, CSSStyleSheet, constructable stylesheets; why render waits for CSS.
From stylesheets to computed values: the CSSOM, the cascade, specificity and layers, matching and invalidation, scoping, then tokens, organisation strategies and loading.
How the browser decides one value per property per element, and what it costs to recompute after a change.
The CSS Object Model: the parsed stylesheets as a tree of rules the engine matches against the DOM and scripts can read.
in practicedocument.styleSheets, CSSStyleSheet, constructable stylesheets; why render waits for CSS.
The algorithm that picks one winning value per property per element from all matching declarations: origin and importance, layer, specificity, then order.
in practiceWhy a later rule loses to a more specific one, and why !important in a library is hostile.
A weight per selector counted as (ids, classes and attributes and pseudo-classes, types and pseudo-elements), compared column by column.
in practiceThe specificity tooltip on a selector in the Styles pane; :where() to drop it to zero, :is() to take its argument's.
@layer declares named layers whose order beats specificity, so a reset or a design system can be overridden by app code without specificity wars.
in practice@layer reset, ds, app; a third-party stylesheet imported into a low layer.
Some properties (color, font, line-height, visibility) pass from parent to child when the child has no value; most layout properties do not.
in practiceWhy setting font on body styles everything; inherit, initial, unset and revert keywords.
The value after the cascade and inheritance, with relative units resolved where possible; what getComputedStyle mostly returns.
in practiceThe Computed pane in DevTools; 2em turns into 32px there.
Engines match selectors right to left: start from the key (rightmost) selector and walk up the ancestors only for elements that match it.
in practiceWhy ".a .b span" checks every span; why deep descendant selectors cost on big DOMs.
A compact probabilistic set of ancestor ids, classes and tags that lets the engine reject descendant selectors quickly without walking the tree.
in practicePart of why selector matching is fast enough in practice.
Working out which elements need restyling after a DOM or class change, using invalidation sets so only affected elements are recomputed.
in practiceThe "Recalculate Style" slice and its "elements affected" count in the Performance panel.
The trace event for the style stage: matching and computing styles for invalidated elements.
in practiceLong purple bars in the Performance panel after a class toggle on a high ancestor.
Styles inside a shadow root apply only within it, and outside styles do not reach in except through inherited properties, custom properties and ::part.
in practiceWeb components and design systems that must survive any host page's CSS.
Styling an element by the size of its container rather than the viewport, so a component adapts wherever it is placed.
in practice@container (min-width: 400px) in a card used in both a sidebar and a main column.
How teams store decisions, keep CSS from colliding, and get styles on screen without a flash.
CSS variables (--name) that cascade and inherit like any property and are resolved at computed-value time, so they can change per element and at runtime.
in practiceDesign tokens, themes, dark mode, per-component overrides; the source of this site's module colours.
Registering a custom property with a type, initial value and inheritance, so it can be animated and validated.
in practiceAnimating a gradient angle or a numeric token smoothly.
Named design decisions (colours, spacing, type, radii, motion) stored once and compiled to CSS variables, platform constants and docs.
in practiceA tokens.json that becomes CSS, iOS and Android values; theming without forking components.
Block, Element, Modifier: a naming convention (.card__title--large) that keeps specificity flat and makes ownership obvious.
in practiceOlder large codebases; still a sane default without CSS modules.
Class names scoped per file at build time by renaming them to unique hashes, so styles cannot collide across components.
in practiceimport styles from "./Card.module.css"; class names like Card_title__x7a2.
Composing small single-purpose classes in markup (Tailwind) instead of writing component stylesheets; the CSS stops growing with features.
in practiceTailwind class strings; a constant-size stylesheet across a growing app.
Writing styles in JavaScript and generating CSS at runtime (styled-components, Emotion) or at build time (vanilla-extract, Linaria, StyleX).
in practiceRuntime libraries cost style recalc on render and conflict with streaming SSR; the industry moved to zero-runtime.
The minimum CSS for above-the-fold content, inlined in the HTML so first paint does not wait for the full stylesheet.
in practiceA style tag in head plus a deferred full stylesheet; LCP improvements on slow networks.
Content painted before its styles arrive, then jumping when they do.
in practiceStylesheets loaded asynchronously without critical CSS; client-only CSS-in-JS on SSR pages.
How text behaves while a web font loads: block (invisible), swap (fallback first), optional (use only if fast).
in practiceInvisible text on slow networks (FOIT); layout shift when the font swaps (FOUT); size-adjust to match fallback metrics.
Direction-relative properties (margin-inline-start, padding-block) that flip automatically for right-to-left and vertical writing modes.
in practiceRTL support for Arabic and Hebrew without an override stylesheet.
A relational pseudo-class that selects an element by what it contains, the long-wanted "parent selector".
in practiceform:has(:invalid), .card:has(img); invalidation cost if used on very high ancestors.