slides.oddbird.net/cq/web-directions/

CSS Containers. What Do They Know?

slides.oddbird.net/cq/web-directions/

@ Web Directions Dev Summit

Containers…

Do they know things?

What are they hiding in there?

As long as I can remember, developers have had questions for containers. What do they know? Do they know stuff?

In 2010 we got Media Queries, the heart of Responsive Web Design

Letting us measure the ‘viewport’ that our page is rendered in – and them adjust our designs based on that. That’s pretty great, until we start adjusting our designs in more complex ways.

So right away developers were asking to measure (or query) not just the viewport, but other elements on the page.

2011-2022 Selector Queries
Element Queries
Container Queries

There have been multiple approaches to this over the years, using a variety of names…

And it became one of the most requested features in CSS.

The browsers heard us asking, and all responded in unison!

Container queries will never be possible on the web. They would cause infinite layout loops.

– The Browsers

But that was the past!

And we live in the future! Sorry, not this future.

We get a global rise in authoritarianism. Sorry, I used to have a joke there about flying cars and spicy auto complete, but… I don’t know.

I’m feeling sad about our industry obsession with fancy new technology, without seriously considering how our algorithms will be used by corporations or governments to do large-scale harm.

What direction are we taking the web? Is it a direction that helps real people, or only the bottom line?

Large language models don’t know anything,

But containers do!

Large language models don’t know anything,

Container Queries! They’ve been supported in all major browsers for almost 2 years now!

/* create some containers */
header, nav, main, aside, footer, section {
container-type: inline-size;
}
/* query those containers */
@container (width > 30em) {
.card { /* style things inside them */ }
}

So how did we get here?

What about those Infinite Layout Loops??!

In order to understand… Why Container Queries Work

We need to understand… Why They Shouldn’t Work

The fact we can control a paper page is really a limitation of that medium.

– John Allsopp, 2000

  • We’re not alone here
  • We’re part of an ecosystem
  • Our decisions impact other people
  • And on the web, we don’t get final say
  • We’re collaborating with browsers
  • Also the people who interact with our sites
  • (super cute in their handy tool belts)
  • On their chosen devices
  • (with varying capabilities)
  • And we’re also collaborating with…
  • aliens 👽
  • Maybe, who knows?

@media prefers-reduced-motion

@supports container-type: inline-size

Graphic design of unknown content with unknown collaborators, on an infinite and unknowable canvas, across operating systems, interfaces, languages, and writing modes

– me

  • (slide)
  • It’s absurd

So, if this is what we want, a web for all - on everything

This is a political vision for the future of the web! A vision that’s built into HTML and CSS from the start! Because tech is always political!

Animation of twitter-like posts appearing

So now, Somehow we have to fit all this content – more and more content all the time 

Onto any screen (or lack of screen) that shows up.

And everything is CSS is based on this tension, content pushing out, and context pushing in

A negotiation between Intrinsic and extrinsic sizes – the content and the container

Extrinsic Sizing

  • Context sizes (available space)
  • width or height set in px, %, em, etc

Intrinsic Sizing

  • auto
  • min-content
  • max-content
  • fit-content

Flow is Very Cool, Actually

Makes The Web Responsive

Responsive Web Design Force Everything Fluid

2010s – only extrinsic sizing

Intrinsic Web Design Combines Fluid & Fixed

2020s – Use intrinsic size as well!

  1. Truly Two-Dimensional Layouts
  2. Combine Fluid & Fixed
  3. Stages of Squishiness
  4. Nested Contexts
  5. Expand & Contract Content
  6. Media Queries, As Needed
  1. Nested Contexts ???

  2. Expand & Contract Content ???

Well there’s your Infinite Layout Loop

Our queries can’t change The Container Being Queried

CSS Containment

contain: size | layout | style | paint

Let’s take a closer look at intrinsic sizing…

For Block Boxes Only The block-size is Intrinsic

(from content)

For Block Boxes The inline-size is Already Extrinsic

(from context)

👎🏼 Block-Size Containment

(too many side effects)

👍🏼 Inline-Size Containment
👍🏼 Size Containment

(both axis)

contain: inline-size layout style;

container-type: inline-size;

We can only Measure The Axis We Contain

We usually only Measure The Inline Axis

(anyway. so there. we don’t even care about your silly block axis, you nerd-faced nerd. leave us alone.)

For reasons… No Default Containers

body > :is(header, nav, main, aside, footer) {
container-type: inline-size;
}

Also Recommended… Name Your Containers

Any number of names

main {
container-type: inline-size;
container-name: layout main;
}
main {
container: layout main / inline-size;
}
@container layout (min-width: 40em) {
.conditional { /* … */ }
}

@container main (min-width: 40em) {
.conditional { /* … */ }
}
@container layout {
.conditional { /* … */ }
}

@container main {
.conditional { /* … */ }
}

Finding Containers

  1. For each matched element
  2. Find the nearest ancestor element with…
    • Required container name
    • Required container type(s)

No self-query Measuring an Ancestor

(can’t change what you measure!)

Bonus! Container Queries Measure Actual Styles

Grid Tracks & Flex Sizing?

No element to measure…

also… Container Query Units

cqw | cqh | cqi | cqb | cqmin | cqmax

@keyframes slide {
0% {translate: calc(0cqi - 100%);}
100% {translate: calc(100cqi);}
}

Default unit container The Small Viewport

Style Queries

@container style(--colors: invert) {}

Style Queries… Only Custom Properties*

* for now

Style Queries… Only Custom Properties*

* for now **
** but maybe forever?

Always Queries Direct Parent

Unless you query a specific container-name

.ಠ_ಠ {
  --(╯°□°)╯: ︵┻━┻;
} is valid CSS.

– Tab Atkins, @tabatkins

???

@container scroll-state(stuck) {}
@container scroll-state(snapped) {}
@container scroll-state(overflowing) {}

Things Containers Know:

  1. Their Size (if contained)
  2. Custom Property Values
  3. Relative Values (like em)
  4. Maybe Some States?? (tbd)