Anchor Positioning Is Disruptive
New layouts will be possible
The more I play with it, the more convinced I am that anchor positioning is going to unlock some surprising new layouts.
What I’ve been working on as an Invited Expert
The CSS Working Group has regular face-to-face meetings (hybrid online/in-person) throughout the year, and they always result in a flurry of activity! Here’s a rundown of some highlights from the last few months, with a focus on the features I maintain.
This is hopefully the first post in a series, providing updates around my work on the CSS Working Group.
These contributions take a lot of time and effort. If you’re interested in supporting our open-source work around CSS, consider becoming a GitHub sponsor, or contributing to our Open Collective.
spec:
Containment, Level 3
Conditional Rules, Level 5
Issue: Reorganizing the Containment specs (#10433)
While Container Queries rely heavily on the idea of ‘containment’, the two features are not tightly intertwined. We’re working to loosen the containment restrictions even more if we can.
To help clarify that relationship, and simplify maintenance of these distinct features, Container Queries are moving from the Containment module (level 3) into the Conditional Rules module (level 5).
During this transition, Container Queries disappeared from any public spec – basically moving back into Editor’s Draft status, after already shipping across browsers. Maybe it was all a dream! But a new Working Draft was published this week. Container Queries are back!
After many issues were raised (thanks for making noise!), we were able to revert the limitation on querying containers across shadow-DOM boundaries. Moving forward, slotted elements should be able to query containers that are defined by a parent shadow-DOM. Container units will also get their sizing from relevant shadow-DOM containers.
For years, the viewport units (vi
/vw
etc)
have been based on the full dimensions of the viewport,
ignoring any possible scrollbars.
That can lead to accidental overflow
if you size something to 100vw
,
and there’s a vertical scrollbar present.
While sometimes frustrating,
that behavior is designed to avoid loop conditions.
Elements sized with viewport units can cause scrollbars,
which would change the size of the unit,
potentially removing the need for scrollbars.
But we don’t have that issue when scrollbar spacing is stable –
using overflow: scroll
or
scrollbar-gutter: stable
–
so the working group resolved to loosen the restriction.
Moving forward, stable scrollbars
will be removed from the viewport measurements.
I requested we do the same
for container-relative cq*
units,
so that will also be fixed.
See the Pen Stable scroll bars & CQ units by @miriamsuzanne on CodePen.
Note that container units
(and container queries generally)
are relative to the
content-box
of a container.
So adding/removing padding
from the container
also/already
changes the size of our cq*
units.
Issue: Can we allow custom properties in dimensional container queries? (#8088)
A bit farther back, but still exciting: we agreed that variables should be allowed in container size queries. In the future, you’ll be able to write:
@container (width > var(--small)) {
/* styles inside larger containers */
}
The variable will resolve on the container. So you won’t be able to make the variable different for each element inside the query, but it can be different for each container being queried:
.container-1 { --small: 20em; }
.container-2 { --small: 600px; }
Issue: Zoom and container queries (#10268)
We clarified the
impact of zoom
on resolving container queries.
Zoom
increases the size of a CSS pixel
in relation to the surrounding layout –
so things appear larger,
but maintain their internal dimensions.
A 50px
box is still 50px
,
we’ve just changed the size of our px
unit.
To keep things simple and consistent,
we determined that containers
should report their own size as they see it.
So a 50px
container at 200%
zoom
will continue to report 50px
in a container query.
This is similar to how relative units
and custom properties resolve
in a container query.
See the Pen Container Queries and Zoom by @miriamsuzanne on CodePen.
If you want to learn more about all the variations of browser and CSS magnification, I’ve got you covered.
I’ve seen a wide range of people worried that “people aren’t using container queries” – but we don’t actually have a way of tracking that! I was curious where this concern comes from, what we’re comparing to, and what expectations we should have about new features showing up in production.
I wrote up my thoughts, summarized by the title of the article: Learn Grid Now, Container Queries Can Wait. We’ll be doing a live stream with Stephanie Eckles (ModernCSS.dev and SmolCSS) about the reasons to use grid, and some of the quick ways to get started.
Spec: Cascading and Inheritance, Level 5
We need
a layer
attribute for the html <link>
element.
We’ve known this for years,
but the issue has been stalled in the WHATWG,
as we try to sort out feature-testing new attributes
(also important!).
While I’d love to have feature queries
in html links as well,
I hope that
separating these two features
might unblock the essential progress on Cascade Layers.
I wrote an explainer,
and asked the w3c
Technical Architecture Group
for review,
as a step towards getting more formal
implementor feedback.
When I have time, I will follow-up with a similar explainer on the need for HTML feature queries.
There’s been a very active discussion around handling unlayered styles in the cascade. By default, unlayered styles have priority over layered styles. This is an essential default in my mind, but there are many use-cases where we would want override the default.
The mega-thread discussion is now eating it’s own tail, but it seems like we have three basic approaches to choose from (and then small variations on each). I have a clear favorite there, but feel free to leave your thoughts as well.
If possible, try not to get lost in alternative naming details – and focus first on the overall behavior of the feature!
Spec: Cascading and Inheritance, Level 6
We recently resolved
a series of issues
related to scope specificity and nesting.
In the future,
you’ll be able to put style declarations
directly into an @scope
rule,
and they will apply to the scope root with no added specificity:
@scope (main) {
/* these styles apply to the :scope (main) */
/* but have no specificity */
color: teal;
border: thick solid;
}
This is equivalent to using :where(:scope)
:
@scope (main) {
/* these styles apply to the :scope (main) */
/* but have no specificity */
:where(:scope) {
color: teal;
border: thick solid;
}
}
The number of option here – and the interactions between features – can be a bit confusing, since each has different implications. While the options and interactions are complex, this resolution keeps the rules consistent for each feature:
@scope
rule itself
does not add specificity to nested styles.
We can think of @scope (<selector>)
as similar to :where(<selector>)
,
which also hides the specificity selectors inside.@scope
rule can have directly-nested styles,
and they apply to the scoping root.
That doesn’t change anything about the selector specificity.:root
, the :scope
selector is a pseudo-class,
and always has the same specificity as any other class
(0,1,0
).&
selector
as being replaced by :is(<parent-selector>)
.
In this case, the parent selector is the scope root selector (main
),
with a specificity of [0,0,1]
.‘Forgiving selector lists’
are handy in many situations,
but are now limited to :is()
and :where()
.
I don’t love that limitation,
but it seems like we’re stuck with it.
For that reason,
scope-start and scope-end selectors
also need to be un-forgiving.
Of course,
we can use :is()
and :where()
inside the scope start/end selectors –
so this is an inconvenience,
but not a change in functionality.
Issue: Can we support implicit scopes in nested settings? (#10497)
Scope and nesting obviously need to work together, since they overlap in some major ways. The basic rules for that interaction are:
header {
@scope (main > &) {
/* the '&' above refers to 'header' */
& h2 { /* this '&' refers to 'main > header' */ }
}
}
I’ve opened a new issue to discuss
implicit scopes when nesting.
If we leave off the scope-start,
can we treat it like (&)
?
header {
@scope { /* should we get an implied 'header' scope? */ }
}
That’s potentially a nice shortcut to have?
Spec: Mixins & Functions, Level 1 (Editor’s Draft)
The Editor’s Draft is underway! It isn’t complete (mixins are missing), but it lays out our current plan for custom CSS functions.
I wrote an article about how mixins should interact with the cascade. I’d be happy for your thoughts!
I’ve heard some browsers expressing doubt about the need for mixins. I plan to start documenting use-cases where CSS mixins would have a large impact. If you have examples, please reach out!
I’m not an editor on the Color spec, but I have some opinions anyway. Browsers currently use ‘channel clipping’ to render out-of-gamut colors, and the results can be wild. I made a comparison pen, to see the difference between browser rendering and what the spec calls for:
See the Pen Color Clipping v Mapping by @miriamsuzanne on CodePen.
Good news! We now have a tentative compromise solution that all browsers agree on. It’s not perfect, but it’s a big improvement over the current state of things.
You can test how it impacts the linked pen
by turning on the css gamut mapping
feature flag
in some Chromium browser versions (go to chrome://flags
).
We talked about this issue (and the potential solution) on our Winging It Live stream last month – along with details of our OddContrast tool for wide-gamut contrast checking.
New layouts will be possible
The more I play with it, the more convinced I am that anchor positioning is going to unlock some surprising new layouts.
Performance, scope, and fallbacks for the anchor positioning polyfill
Our sponsors are supporting the continued development of the CSS Anchor Positioning Polyfill. Here’s a summary of the latest updates.
Are we measuring what we meant to measure?
There’s been a lot of interest in the results of the annual State of CSS survey, but are we asking all the right questions?