Archived:
🚚 This content is being maintained elsewhere. Our notes are likely out-of-date.
See the latest specification for details.
Existing Specifications ¶
CSS Selectors - Level 4 ¶
-
Scoped Selectors that only refer to a subtree or fragment of the document
When a selector is scoped, it matches an element only if the element is a descendant of the scoping root. (The rest of the selector can match unrestricted; it’s only the final matched elements that must be within the scope.)
-
Reference Element (
:scope
) pseudo-class (broad browser support)
In CSS, this is the same as :root
, since there is no way to scope elements. However, it is used by JS APIs to refer to the base element of e.g. element.querySelector()
“Specifications intending for this pseudo-class to match specific elements rather than the document’s root element must define either a scoping root (if using scoped selectors) or an explicit set of :scope elements.”
CSS Scoping - Level 1 ¶
The latest draft is primarily concerned with Custom Elements & Shadow DOM.
The First Public Working Draft had more scoping features that have since been removed:
A <style scoped>
attribute,
which would apply to sibling elements and their descendants.
This had a few limitations:
- Need to repeat in the DOM for every instance of the scope
- Need a distinct stylesheet for each scope
It also included CSS @scope
blocks,
which would help alleviate both issues.
Scoping has two primary effects:
- The selector of the scoped style rule is restricted to match only elements within scope.
- The cascade prioritizes scoped rules over un-scoped ones,
regardless of specificity.
- This results in proximity-weighting across scopes
- But also means scope overrides everything
CSS Cascade - Level 4 ¶
- Removes “scoping” from the cascade sort criteria, because it has not been implemented.
- Adds encapsulation context
to the cascade, for handling Shadow DOM
- Outer context wins for normal layer conflicts
- Inner context wins for
!important
layer conflicts
Ecosystem ¶
Naming conventions (BEM) ¶
To show that .element
is not just inside .block
,
but belongs to it –
BEM requires authors to manually namespace one class
using both names:
/* .element scoped to .block */
.block-element { /* ... */ }
JS tools & frameworks ¶
CSS Modules, Vue, Styled-JSX, and other tools often use a similar pattern (with slight changes to syntax):
/* a component & it's children get a unique attribute to select against */
.component[scope=component] { /* ... */ }
.element[scope=component] { /* ... */ }
/* nested component containers are part of both outer & inner scope */
.sub-component[scope=component],
.sub-component[scope=sub-component] { /* ... */ }
/* but elements inside a nested component only have inner scope */
.sub-element[scope=sub-component] { /* ... */ }
- The donut is achieved by selectively adding attributes
- Proximity-weight is achieved only through limiting the donut of scope
- Added selector gives scoped styles some (but very little) extra specificity weight in the cascade
CSSWG draft issues ¶
- Bring Back Scope:
- Selector Boundaries
- CSS Namespaces
- And stated priorities
Yu Han’s notes & proposal ¶
This proposal has two parts, designed to build on top of existing shadow DOM logic.
- Allow shadow-DOM elements to opt-in to global styles
- Allow light-DOM elements to opt-in to style isolation