Cascade & scope
The at-rules that bring other style sheets in, put rules into cascade layers that win or lose as a group, declare XML namespaces for selectors, and limit a set of rules to one part of the document. Media and feature conditions are under Conditional rules; the pseudo-classes used with them, such as :scope, are under Selectors.
Importing & layering
@import
Loads another style sheet and treats its rules as if they were written in place of the @import. It must come before every other rule in the sheet except @charset and @layer statements; an @import placed later is ignored.
| Syntax | @import [ <url> | <string> ] [[ layer | layer( <layer-name> ) ] || [ scope | scope( <scope-start> | <scope-boundaries> ) ] || <supports-import-condition>]? <media-import-condition> ; |
|---|---|
| Support | Chrome 1 · Firefox 1 · Safari 1 |
| Spec | css-cascade-6 |
| Condition | Effect | Support |
|---|---|---|
layer / layer(<layer-name>) | Puts the imported rules into a new anonymous layer, or into the named layer. | Chrome 99 · Firefox 97 · Safari 15.4 |
supports(…) | Imports the sheet only if the browser supports the declaration or condition, as in @supports. | Chrome 122 · Firefox 115 · Safari 17.5 |
| Media query list | Imports the sheet only when the media query matches. | Chrome 1 · Firefox 1 · Safari 1 |
@import url("reset.css") layer(reset);
@import url("grid.css") layer(layout) supports(display: grid) screen;
Each @import is a separate request that the browser cannot start until it has read the importing sheet, so a chain of imports loads slowly. Bundling or several <link> elements avoid the wait.
@layer
Declares a cascade layer. Layers decide which rules win before specificity does: a rule in a later layer beats a rule in an earlier one however specific the earlier selector is. Styles in no layer beat every layer.
| Syntax | @layer <layer-name>? { <rule-list> } | @layer <layer-name>#; |
|---|---|
| Support | Chrome 99 · Firefox 97 · Safari 15.4 |
| Spec | css-cascade-5 |
The rule has two forms. The statement form, @layer a, b, c;, only declares names, which fixes the order of the layers at the point they first appear. The block form, @layer name { … }, adds rules to a layer, creating it if it does not exist yet. A block with no name creates an anonymous layer that nothing else can add to. A <layer-name> may be dotted, as in components.buttons, to name a layer nested inside another.
/* fix the order first: later names win */
@layer reset, base, components;
@layer components {
.button { color: white; }
}
@layer base {
#main a { color: blue; }
}
a.button { color: black; } /* unlayered: beats both */
components beat base, even though base comes later in the file and has the stronger selector.For !important declarations the order is reversed: an important declaration in an earlier layer beats one in a later layer, and both beat important unlayered styles.
Namespaces & scope
@namespace
Declares an XML namespace for the style sheet, either as the default for type selectors or bound to a prefix used as prefix|name. It matters only for documents that mix namespaces, such as SVG or MathML served as XML.
| Syntax | @namespace <namespace-prefix>? [ <string> | <url> ] ; |
|---|---|
| Support | Chrome 1 · Firefox 1 · Safari 1 |
| Spec | css-namespaces-3 |
@namespace svg url("http://www.w3.org/2000/svg");
svg|a { fill: currentColor; } /* only SVG a elements, not HTML links */
@namespace rules must come after any @charset and @import rules and before all other rules. The prefix applies only within the sheet that declares it.
@scope
Limits the rules inside it to elements within a scoping root, optionally stopping at a lower boundary called the scoping limit. Inside the block, :scope matches the root itself.
| Syntax | @scope <scope-boundaries>? { <block-contents> } |
|---|---|
| Support | Chrome 118 · Firefox 146 · Safari 26.4 |
| Spec | css-cascade-6 |
<scope-boundaries> is (<scope-start>) followed optionally by to (<scope-end>), where each part is a selector list. Written with a limit it makes a donut scope: the rules apply from the root down to, but not inside, the limit.
@scope (.card) to (.card-content) {
img { border: 2px solid; }
:scope { padding: 1rem; }
}
When two scoped rules conflict with equal specificity, the one whose scoping root is the nearer ancestor wins. An @scope with no prelude inside a <style> element is scoped to that element's parent.