slides.oddbird.net/csswg/chrome/

Proposal for Container Queries

slides.oddbird.net/csswg/chrome/

@ Google Developer Experts
  • Media queries let us respond to viewport
  • Same element in multiple containers, viewport isn’t useful
  • Respond to containers instead

No matter how those containers are nested.

Layout Loops

CSS Context vs Content

But trying to measure a “container” in CSS, and then make changes based on that measurement, poses a bit of a paradox.

One of the coolest responsive features in CSS, which we don’t talk about nearly enough, is the way we calculate layout based on both context and content. Add more content, and a container will try to grow, but it might also be constrained by context, or explicit sizing.

That’s very cool, but if you add container queries, it becomes an infinite loop: as the container gets larger, we make the content smaller, which makes the container smaller, which makes the content larger.

2010-2020 🚧 Laying Foundations 🚧

So for a long time, this seemed impossible to implement. But behind the scenes, a lot of people have been laying the groundwork in browsers.

2020 Proposals

  • David Baron: @container
    limited by containment
  • Brian Kardell: switch()
    limited to paint

Last year two proposals emerged, showing different ways we might pull this off. Both are interesting, but David Baron’s approach has the most momentum right now, and I’ve been working on it to flesh out some of the details, and start writing a specification.

The first thing we need to do is define our containers 

Anything we want to be able to measure.

In order to avoid any layout loops, we need to turn off content-based sizing. Our containers need to be sized without reference to anything inside it.

.container {
contain: size layout style;
}

We already have a property for this! It’s called contain, and allows us to “contain” various types of things.

Size containment turns off content-based sizing, layout containment is kinda like a clearfix – wrapping around floats and margins – and style containment keeps list-counters from leaking out.

And we’re going to need all three of these for our container queries work.

2D size containment Is Too Restrictive

But size-containment is… bad in most cases. It’s just not possible to build all our containers with explicit widths and heights! We usually need one axis to be fluid, so that extra content has somewhere to go.

Most layouts work by containing the width, or the inline-dimension, and allowing the height to grow or shrink with the content. So we’re adding an option to make single-axis containment possible.

Contain inline-size.

We’re not sure if we can also allow a block-size values here. That needs some more experimenting.

.sidebar, main, .grid-item {
contain: inline-size layout style;
}

In our initial proposal, applying the appropriate containment – layout and 1d or 2d size – creates a container.

That’s how the Chrome prototype currently works, but you can see it’s a lot to remember, and it’s not obvious what’s going on.

So we’re working on a simpler syntax here.

Instead of specifying all the containment required, we just say what type of container we want – or what we want to query. In this case we want to query the inline size. Browsers can take that, and apply the right containment in the background.

This syntax is still very much in development, so it could change a lot. There’s some concern around having a container property that is so similar to the contain property.

Once we have containers, we can begin to query them!

@container (min-width: 40em) {
.card { /* ... */ }
h2 { /* ... */ }
}

A container-query looks exactly like a media-query, but with at-container instead of at-media. And each element will query the size of it’s nearest ancestor container.

That’s another important limitation to make sure there are no loops. Container’s can’t query themselves.

<div class="container">
<div class="container">
<div class="container">
We can nest containers!
</div>
</div>
</div>

We can have containers inside of containers 

.container { container: inline; }

@container (width > 30em) {
.container { padding: 2em; }
}

And we can change containers inside a container query. But each container will respond to the size of its parent container.

Chrome Prototype

  1. Download/Update Chrome Canary
  2. Go to chrome://flags in the URL bar
  3. Search for “CSS Container Queries” & enable it
  4. You’ll need to restart after turning it on

Chrome already has a prototype, and you can start playing with it behind a feature flag. I’ve started collecting codepen demos to help you get started.

But why don’t I just show you? I’ve set up two containers on the page, each with one card using a media-query, and one card using a container query. The media queries all trigger at the same time, but the container queries depend on the size of the container.

My coworker David Herron, made this one showing the same blockquote with three different designs based on the size of the container.

In some cases, like inside flexbox or grid, there is no outside container that will tell us the actual space available for each item. But we can get around that by adding a container around each component – in this case div.card is wrapping each article. The outer div establishes a container, and the inner article can query it.

Max Böck has created this bookstore demo with self-contained web components. Each component host element is a container, and everything inside the component adjusts based on available size.

Of course, we can also get creative! Jhey Tompkins made these interactive blinds that get smaller as the container gets bigger. Because CSS doesn’t have to be practical to be awesome.

@container (width > 30em) { /* CQ support */ }

/* actual syntax TBD */
@supports not (container: inline) {
@media (width > 40em) { /* no CQ support */ }
}

I’m recording this in advance, so check back. I’ll share the link to my slides, and update this one with more resources before the conference starts.

Building on the existing features of CSS 

But particularly the overlap between the two main goals of CSS: to make responsive 

and reusable styles. Building components that are inherently responsive 

There’s already been a lot of progress in this space, with tools like grid & flexbox & aspect-ratios – but Container Queries help us get a little closer.