Skip to content
docsv0.31.1

CssScoper

Rewrites a component's stylesheet so its rules can only reach that component. A component declares plain CSS against the house tokens and never repeats its own name in a selector; this puts the name in, once, for every top-level rule. That is what lets two components written by two strangers use `.field` for different things on the same page without either author knowing the other exists — the alternative being the convention-and-goodwill scheme that produced one 4,849-line bundle nobody could safely edit. Three rules govern what is rewritten, and the two exceptions matter more than the rule: - A rule's SELECTOR is prefixed; its BODY is copied verbatim. Native CSS nesting therefore keeps working untouched — a nested rule already inherits its parent's now-scoped selector, so prefixing it again would scope it twice. - Conditional at-rules (`@media`, `@supports`, `@container`, `@layer` with a block, `@scope`) are recursed into, because their bodies hold ordinary rules. - Everything else at-rule-shaped is copied verbatim. `@keyframes` is the reason: its "selectors" are `from`, `to` and percentages, and prefixing those silently kills the animation. `:host` names the component's own root, the way it does in shadow DOM. Its plain-CSS inertness is the point: a component stylesheet that somehow reaches the page unscoped styles nothing, instead of styling the document like a stray `:root` would.

CssScoper::scope()

public function scope(string $css, string $scope): string

Confines a stylesheet to one component, returning CSS the page can embed as-is.

Parameters

Parameters of scope()
NameTypeDescription
$cssstringThe component's stylesheet, as authored.
$scopestringA selector matching the component root (e.g. `[data-milpa-component="input"]`).