2020 Proposals David Baron: @container limited by containment Brian Kardell: switch() limited to paint
1D Size Containment (proposed by David Baron) inline-size (most useful & most possible) block-size? width? height?
@container .sidebar, main, .grid-item (width > 40em) { .card { /* ... card layout ... */ } h2 { /* ... responsive type? ... */ }}
/* query *nearest contained ancestor* */@container (width > 40em) { .card { /* ... */ } h2 { /* ... */ }}
.card { display: grid; grid-gap: 0.5em;}@container (min-width: 40ch) { .card { grid-template: "img text" auto / minmax(10em, 30%) 1fr; grid-gap: 1em; }}
h2 { font-size: 1.2em; line-height: 1.4;}@container (min-width: 40ch) { h2 { font-size: 1.6em; line-height: 1.2; }}
Rules in @container apply when… There’s an ancestor with appropriate containment The laid out size of the most immediate container matches the query condition
Query against computed values em queries can resolve based on computed font size? Can we query more than just dimensions?
Alternative selector syntax @container (inline-size < 40em) { .card { /* ... */ }}.card:container(inline-size < 40em) { /* ... */}
Other Questions What else can we query besides dimensions? Can block axis be contained in 1D? (WIP) Container-width & -height units? Container-based image srcset and sizes? Can containment be applied inside a container query? How does the initial container work? Can shadow-DOM queries resolve against host containers?
The Scope Goal Avoid Naming Conflicts (across large teams & projects) By Expressing Membership (through lower boundaries & proximity)
.light-theme a { color: purple; }.dark-theme a { color: plum; } <div class="dark-theme"> <a href="#">plum</a> <div class="light-theme"> <a href="#">also plum???</a> </div></div>
Encapsulation is High-Impact & DOM-Centric… (non-goals for this proposal) 1:1 relationship widget/scope Boundaries defined in the DOM Styles are isolated by default Proximity overrides specificity
Improving Encapsulation (non-goals for this proposal) Declarative Shadow-DOM Shadow-DOM elements opt-in to global styles Light-DOM elements opt-in to style isolation
Scope is Low-Impact & Style-Centric… (goals for this proposal) Scopes are defined in CSS …can be re-used across components …can overlap & cascade together Priority is mostly handled by ownership Specificity overrides proximity
Expressing Membership .post__title { /* BEM */ }.title[data-scope=post] { /* … */ }.x1234 { /* … */ }
The @scope rule /* @scope (<root>#) [to (<boundary>#)]? { … } */@scope (.tabs) to (.panel) { /* … */ }
The :scope selector @scope (.tabs) to (.panel) { :scope { /* targeting the scope root */ } .light-theme :scope .tab { /* contextual styles */ }}
For boundary-matching @scope (.tabs) to (.tabs) { /* to (:scope .tabs) */}@scope (.tabs) to (:scope) { /* single-element scope (needs use-cases?) */}
For selector-matching @scope (.tabs) to (.panel, .tabs) { .tab { /* :scope .tab:not(:scope :is(.panel, .tabs) .tab) */ } .tabs { /* :scope .tabs:not(:scope :is(.panel, .tabs) .tabs) */ }}
For specificity @scope (.tabs, #options) { .tab { /* specificity: [1, 1, 0] as-though: :is(.tabs, #options) .tab */ }}
For proximity @scope (.light-theme) { a { color: purple; } }@scope (.dark-theme) { a { color: plum; } } <div class="dark-theme"> <a href="#">plum</a> <div class="light-theme"> <a href="#">purple</a> </div></div>
For proximity @scope (.light-theme) { a { color: purple; } }@scope (.dark-theme) { a { color: plum; } } <div class="dark-theme light-theme"> <a href="#">plum (source order)</a></div>
Specificity takes precedence @scope (.hero) { #call-to-action { text-decoration: none; } }@scope (.typeset) { a { text-decoration: undeline; } } <header class="hero"> <div class="typeset"> <a id="call-to-action">purple (specificity)</a> </div></header>
Potential “Donut” Selector? concept suggested by Lea Verou in TAG review @scope (.tabset) to (.panel) { .tab { /* ... */ } }.tab:in(.tabset / .panel) { /* ... */ }
Scope Open Questions Scope-root selectors inside Shadow-DOM Tree-abiding pseudo-elements as scope-roots JS API for fetching “donut scope” Syntax for selecting past boundary?