Skip

Improving CSS Architecture with Cascade Layers, Container Queries, Scope

Presenter: Miriam Suzanne
Duration: 6 min
Slides: download

CSS is intentionally contextual, adapting to a range of user needs and interfaces – and the cascade makes that possible. But as the Web becomes more powerful, it’s clear that design engineers need more tools to organize and maintain larger code-bases across larger teams.

All demos

Skip

Slides & Video

Slide 0

I want to quickly show you three CSS features that we’re working on, to help teams manage the overall architecture of their CSS.

Slide 3

First, we wanted to address some of the pain points around selectors and specificity.

Slide 4

Specificity is based on the assumption that generic selectors are also lower priority, and more narrowly targeted selectors are higher priority.

Slide 5

This is a rough approximation of the layers in our code – But it’s not perfect.

Slide 6

And authors don’t have much direct control.

The act of layering is intertwined with the need to select elements.

Slide 7

Cascade Layers are designed to give authors more direct control, to describe our own custom layers of the cascade.

Slide 8

We can define a layer, give it a name, and add styles to it using either the at-layer rule.

Slide 9

Or by adding a layer function to imports, or both.

Slide 10

Layers stack in the order they were first defined, with un-layered styles at the bottom, and the last layer at the top.

Selectors inside the components layer here, will take priority over all the other layers.

Slide 11

But we don’t need to keep all our layered styles in that same order.

The layer priority is based on when a layer name first appears.

Slide 12

So we can even establish our desired layer order up-front, by using the layer rule without any styles – just a layer name or list of names.

Once they’re established, we can add to those layers in any order, and our code will slot into place.

Slide 13

We can also nest layers as needed – and reference nested layers directly with a dot notation.

Slide 14

Or create anonymous layers that are maintained in a single location.

Slide 15

This spec is currently a Working Draft, and has become fairly stable.

Slide 16

Both Firefox and Chrome already have prototypes available behind flags, and there’s also been significant progress on the Webkit issue.

Slide 17

The next feature is also about how selectors work.

With “scope”, we’re trying to address two closely related issues that come up regularly, and drive people to use tools & conventions like BEM syntax or CSS-in-JS.

Slide 18

The first goal is to avoid naming conflicts as our projects grow.

Slide 19

Which we can solve by focusing on our second goal: expressing “membership” or “ownership” in our selectors.

Slide 20

While nested selectors might seem like a way to express membership – in this case a title that is inside a post.

Slide 21

That’s not quite the same thing as a post-title.

The first one only describes a nested structure, but the second describes a more clear membership in a component pattern.

Not all the titles in a post, just the title that belongs to the post.

Slide 22

Another way to think about this is to say that some components have lower boundaries.

The component itself is a “donut” with a slot in the middle for content.

We should be able to style these donut components, without worrying that we might accidentally style everything inside them by mistake.

Slide 23

There are some similarities between scope and shadow-DOM encapsulation.

But Shadow boundaries are defined in the DOM, so that each element has a single scope, and styles are strongly isolated from getting in or out.

They're never allowed to overlap at all.

Slide 24

Where scopes are defined entirely in CSS – more fluid, able to overlap, and integrate more smoothly with global design systems.

Slide 25

The current proposal uses an at-scope rule, which accepts both a scope-root selector (in this case media) and a lower-boundary selector (in this case content).

Any selectors inside the at-rule only match elements between a matched root element and any lower-boundary descendants.

Slide 26

We’re also considering how scope proximity might become part of the cascade.

When two styles have the same specificity we could give priority to the “closer” scope-root before falling back to source-order.

Slide 27

There has also been talk about adding some form of lower-boundary or donut selector syntax, to write more targeted selectors without the at-rule or proximity weighting.

Slide 28

This is still in very early design discussions, but we’re happy to get any feedback.

Slide 29

And that brings us to Container Queries – one of the most requested features over the last decade.

Slide 30

While media queries let us respond to size of the viewport If we have those same elements in different size containers, we can see that the viewport doesn't give us the information we want So we want some way to reference the container itself and allow each of these cards to layout differently based on the container it's inside of.

Slide 31

But this type of query could lead to an infinite layout loop.

So the first thing we need to do is define our containers – any element the we want to query – and turn off content-based sizing on those elements.

Slide 32

We can do something similar with the contain property, but the current options are a little too heavy-handed.

Slide 33

We usually want to contain only the width of an element, or the inline-dimension, and allow the height or block dimension to grow and shrink with the content.

This isn’t entirely solved, yet, but we do have a prototype, and we’re confident that there’s a path forward.

Slide 34

But authors wont set that containment directly.

Instead, we’ll define the type of container we want.

Slide 35

What dimensions we need to query – And then any element can query the container it is in – its nearest ancestor that’s been defined as a container.

This container-query looks exactly like a media-query, but with at-container instead of at-media.

Slide 36

And if you don’t want to rely on the nearest container, you can also give containers names, and only query containers with a specific name.

Slide 37

Or only query a specific container type.

Slide 38

Chrome Canary already has a prototype, and you can start playing with it behind a feature flag.

Slide 39

Max Böck has created this bookstore demo with self-contained web components.

Each host element is a container, and everything inside the component adjusts based on available size.

Slide 40

We’re also working on container-relative units, similar to vw, vh, vmin, vmax, but a percentage of the container size rather than the viewport.

These are also supported in the Chrome Canary prototype.

Slide 41

Here’s a demo from Scott Kellum showing query units in action.

Slide 42

We’re also working on queries that aren’t about the container size.

The exact syntax is not established yet, but we might be able to query the actual value of a property.

Slide 43

Or the current state of a container.

Is it position-sticky, and currently in a “stuck” state?

Slide 44

This is an editor’s draft, just waiting on the details of single-axis containment before we move it to First Public Working Draft, and start looking for more implementations.

Slide 45

All of these features are designed to work together, building on the existing features of CSS.

we’re excited to see what people build with these new tools, and always open to your feedback.

Skip

All Demos

Skip

Sponsors

Title sponsor

Coil Technologies,

Media sponsor

Legible

Silver exhibitor

Movement for an open web

Bronze exhibitor

Igalia

For further details, contact sponsorship@w3.org