Container Queries CSS (un)expected revolution

CSS Day Logo
Faenza,

Massimo Artizzu Web Dev Manager, Antreem

My face

Massimo Artizzu

Web Dev Manager
Antreem@Gellify

GitHub logo / Mastodon logo / Twitter logo / dev.to logo @MaxArt2501

You can find these slides at

QR Code for the presentation's link maxart2501.github.io/css-cont-queries-talk/css-day/

Before…

Vintage photo of an ox cart Logo of JavaScript Logo of CSS It was not 4 years ago that I was complaining about how things were moving slowly for CSS. Grids were the last new things and it took years to be refined and specified, and even if browsers were rather quick to implement it

Houdini

Harry Houdini trying to get free of chains So that I talked about CSS Houdini and how it supposed to let us break free of that situation. Now, the project did some things that promised, but not every one of its APIs has been fully specified - let alone implemented in browsers, not even Chrome. And now the initial push has basically vanished.

Now…

Logical properties

.box {
  padding-inline-start: 1em;
  margin-block: 2em;
  text-align: start;
  inset: 0;
}

Color Functions

.rainbow {
  color: lch(80% 100 50 / 0.5);
  color: color(display-p3 0.9 0 0.5);
  color: color-mix(in rgb, salmon 30%, blue);
}

Cascade Layers

Vintage photo of a visibly confused person

:has()

form:has(:invalid) { border: red; }

article:has(> header) { margin-top: 1em; }

h1:has(+ p) { margin-bottom: .5em; }

IE is dead

Vintage photo of a cheering crowd

And even more…

conic-gradient() aspect-ratio

CSS Isolation

Media Queries lvl4+

Variable Fonts

@supports

Counter Styles

Shadow Parts

Scroll Snap

min() clamp() :focus-visible

But a long time ago…

@media

The problem with media queries

Vintage picture of tailors takeing measurement
@media (min-width: 1024px) {
  main {
    grid-template-columns:
      24rem 1fr 24rem
  }
}
Vintage photo of a theater

Only for viewports

What about components?

Clip of a confused Stan Laurel
A picture of a fake old newspaper
Different sizes…
… different layouts

How we used to do it

flex-wrap: wrap Picture of a man on a penny farthing Picture of a man on a penny farthing grid-template-columns: repeat(auto-fi*, minmax(10rem, 1fr)) I don't know you, but I personally have to check the difference between auto-fill and auto-fit *every time* I need to use one of them.

Element queries

<div class="widget-name">
  <h2>Element responsiveness FTW!</h2>
</div>
.widget-name h2 {
  font-size: 12px;
}
.widget-name[min-width~="400px"] h2 {
  font-size: 18px;
}
Logo of JavaScript

“Can't we just…?”

.painting {
  background: url(monalisa.jpg);

  @element (min-width: 8rem) {
    background: url(spring.jpg);
  }
}

The Problem

.box-o-stuff {
  width: 1000px;

  @element (min-width: 800px) {
    width: 500px;
  }
}
.box-o-stuff {
  @element (max-width: 800px) {
    div { width: 1000px; }
  }
}
Not only the element can be given "contradictory" sizes, but also its descendants can alter its sizes so that circular size recalculations take place. Among the first proposed solution was to limit these recalculations to 3, but it wasn't ideal anyway.
“1000px!”
An old style boxer facing right
“500px!”
An old style boxer facing right

So… how can
we solve that?

Vintage picture of a woman thinking in front of a typewriter

Container Queries

CSS Containment

CSS Container queries

A handshake

Containing things…

contain:
  • layout
  • size
  • paint
  • style

Element containment is introduced by the property `contain`, which can 4 different values or a combination of those.

These values state to the CSS engine that one or more aspects of the process of element rendering are contained inside the element, in the manners we're now going to explore.

Layout containment

The internal layout is isolated: it can't affect the external layout, nor external factors can affect the internal layout.

It's like a new “viewport”.

Ye olde news of the worlde

A distinguished man tipping his top hat

LOREM ipsum dolor sit amet, consectetur adipisicing elit. Tenetur, ipsam debitis omnis reiciendis, id nisi veritatis maiores distinctio quae voluptate esse aliquam eaque laboriosam unde, ad eos ratione asperiores dolores? Corporis accusantium, ipsa rerum temporibus voluptates ducimus deserunt accusamus ullam possimus assumenda sunt dolore voluptatibus quod et consequuntur consequatur quae magni? Fugiat, culpa velit. Fugiat dolor ad laudantium aliquam beatae? Dolorum, repudiandae blanditiis quo architecto id totam?

Here’s no contain

SUNT est amet cum incidunt ab placeat repellendus, provident vel unde expedita numquam eius. Ipsum blanditiis officiis delectus soluta. Labore. Possimus nostrum amet sint sed aliquid tempore ratione quaerat incidunt saepe, placeat officia quas molestiae dolore non ut expedita vitae corrupti temporibus! Dolor voluptatem harum itaque impedit accusamus et aut? Possimus veniam tempora cupiditate impedit amet quod error quidem libero, illum atque expedita? Laborum ducimus fugit excepturi itaque eum sapiente possimus vero saepe dicta quo. Quia omnis odio placeat quis! Fugiat dolor ad laudantium aliquam beatae?

Ye olde news of the worlde

A distinguished man tipping his top hat

LOREM ipsum dolor sit amet, consectetur adipisicing elit. Tenetur, ipsam debitis omnis reiciendis, id nisi veritatis maiores distinctio quae voluptate esse aliquam eaque laboriosam unde, ad eos ratione asperiores dolores? Corporis accusantium, ipsa rerum temporibus voluptates ducimus deserunt accusamus ullam possimus assumenda sunt dolore voluptatibus quod et consequuntur consequatur quae magni? Fugiat, culpa velit. Fugiat dolor ad laudantium aliquam beatae? Dolorum, repudiandae blanditiis quo architecto id totam?

Lo, here’s contain: layout

SUNT est amet cum incidunt ab placeat repellendus, provident vel unde expedita numquam eius. Ipsum blanditiis officiis delectus soluta. Labore. Possimus nostrum amet sint sed aliquid tempore ratione quaerat incidunt saepe, placeat officia quas molestiae dolore non ut expedita vitae corrupti temporibus! Dolor voluptatem harum itaque impedit accusamus et aut? Possimus veniam tempora cupiditate impedit amet quod error quidem libero, illum atque expedita? Laborum ducimus fugit excepturi itaque eum sapiente possimus vero saepe dicta quo. Quia omnis odio placeat quis! Fugiat dolor ad laudantium aliquam beatae?

Size containment

The element's size is not determined by its descendants.

Ye olde news of the worlde

A distinguished man tipping his top hat

LOREM ipsum dolor sit amet, consectetur adipisicing elit. Tenetur, ipsam debitis omnis reiciendis, id nisi veritatis maiores distinctio quae voluptate esse aliquam eaque laboriosam unde, ad eos ratione asperiores dolores? Corporis accusantium, ipsa rerum temporibus voluptates ducimus deserunt accusamus ullam possimus assumenda sunt dolore voluptatibus quod et consequuntur consequatur quae magni? Fugiat, culpa velit. Fugiat dolor ad laudantium aliquam beatae? Dolorum, repudiandae blanditiis quo architecto id totam?

SUNT est amet cum incidunt ab placeat repellendus, provident vel unde expedita numquam eius. Ipsum blanditiis officiis delectus soluta. Labore. Possimus nostrum amet sint sed aliquid tempore ratione quaerat incidunt saepe, placeat officia quas molestiae dolore non ut expedita vitae corrupti temporibus! Dolor voluptatem harum itaque impedit accusamus et aut? Possimus veniam tempora cupiditate impedit amet quod error quidem libero, illum atque expedita?

Hark, contain: size!

A distinguished man tipping his top hat

LOREM ipsum dolor sit amet, consectetur adipisicing elit. Tenetur, ipsam debitis omnis reiciendis, id nisi veritatis maiores distinctio quae voluptate esse aliquam eaque laboriosam unde, ad eos ratione asperiores dolores? Corporis accusantium, ipsa rerum temporibus voluptates ducimus deserunt accusamus ullam possimus assumenda sunt dolore voluptatibus quod et consequuntur consequatur quae magni? Fugiat, culpa velit. Fugiat dolor ad laudantium aliquam beatae? Dolorum, repudiandae blanditiis quo architecto id totam?

SUNT est amet cum incidunt ab placeat repellendus, provident vel unde expedita numquam eius. Ipsum blanditiis officiis delectus soluta. Labore. Possimus nostrum amet sint sed aliquid tempore ratione quaerat incidunt saepe, placeat officia quas molestiae dolore non ut expedita vitae corrupti temporibus! Dolor voluptatem harum itaque impedit accusamus et aut? Possimus veniam tempora cupiditate impedit amet quod error quidem libero, illum atque expedita?

Paint containment

Nothing is rendered outside the element's boundaries.

Absolutely positioned img

A distinguished man tipping his top hat

LOREM ipsum dolor sit amet, consectetur adipisicing elit. Tenetur, ipsam debitis omnis reiciendis, id nisi veritatis maiores distinctio quae voluptate esse aliquam eaque laboriosam unde, ad eos ratione asperiores dolores? Corporis accusantium, ipsa rerum temporibus voluptates ducimus deserunt accusamus ullam possimus assumenda sunt dolore voluptatibus quod et consequuntur consequatur quae magni? Fugiat, culpa velit. Fugiat dolor ad laudantium aliquam beatae? Dolorum, repudiandae blanditiis quo architecto id totam? Pariatur consequuntur inventore iusto facere perspiciatis, quas minus illum. Consequatur nobis explicabo, iusto iure quia exercitationem commodi quisquam.

And lo, contain: paint

A distinguished man tipping his top hat

LOREM ipsum dolor sit amet, consectetur adipisicing elit. Tenetur, ipsam debitis omnis reiciendis, id nisi veritatis maiores distinctio quae voluptate esse aliquam eaque laboriosam unde, ad eos ratione asperiores dolores? Corporis accusantium, ipsa rerum temporibus voluptates ducimus deserunt accusamus ullam possimus assumenda sunt dolore voluptatibus quod et consequuntur consequatur quae magni? Fugiat, culpa velit. Fugiat dolor ad laudantium aliquam beatae? Dolorum, repudiandae blanditiis quo architecto id totam? Pariatur consequuntur inventore iusto facere perspiciatis, quas minus illum.

Style containment

Not style encapsulation. It's just for counters.

p::before {
  content: counter(num);
}

What do we need?

Container Queries, take 2

Alfred Hitchock holding a clapperboard for his film 'Psycho'

Declaring a container

.container {
  container-type: inline-size;
}

We're going to use the new property `container-type`, and not `contain` that we've just seen. In the first drafts of the spec, `contain` was used, but that was changed afterwards as the two specs specialized in performance (containment) and in capabilities (container queries).

Nonetheless, defining `container-type` automatically turns on containment for `layout` and `size` or `inline-size`, depending on the value of `container-type`.

.container {
  container-type: inline-size;
}
.frame {
  background: url(monalisa.jpg);
}

@container (width > 8rem) {
  .frame {
    background: url(spring.jpg);
  }
}
<div class="container">
  <div class="frame"></div>
</div>

Nested containers?

<main class="container">
  <header>...</header>
  <aside>...</aside>
  <section>
    <article class="container">
      <p>...</p>
    </article>
  </section>
</main>
main.container {
  container-name: main;
  /* Or together: */
  container: main / inline-size;
}
p { font-size: 150%; }
@container main (width > 40rem) {
  p { font-size: 200%; }
}

About fonts…
Remember this?

@media (width > 769px) {
  h2 {
    font-size: clamp(2rem, (100vw - 768px) / 40, 3rem);
  }
}
A marker circle around '100vw'

We still can do it!

Person wins the race

Despite all the common things, a person arrived first at the Grand Prix. Another person, second.
Photo of a driver inside a race car from then '30s
At the wheel, there’s a real person. The car has four wheels and all kinds of moving parts.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laborum earum animi excepturi enim rerum unde commodi incidunt, officiis modi sed libero. Fugit, dolore veniam? Qui ut inventore neque corrupti totam.

Ut repellat veniam aspernatur commodi quis! Excepturi commodi sequi reprehenderit nam rerum fugit obcaecati ullam ea facere veniam id labore, iste velit dignissimos soluta perferendis mollitia consequatur dicta, maxime quia.

Voluptate architecto, quasi quidem consequuntur reiciendis delectus doloribus. Reiciendis sunt omnis accusantium temporibus voluptas ex quia quos hic corrupti sint, illum cum doloremque asperiores quae aut saepe laudantium, ducimus repudiandae?

Harum esse sed nemo ex praesentium incidunt, beatae ad quam! Laboriosam iusto, corrupti nulla numquam beatae animi neque magnam impedit odio sed quisquam fuga dolor possimus velit, enim aliquid! Nam.

Debitis blanditiis ut cumque possimus, impedit nulla culpa nobis placeat distinctio sed modi velit obcaecati tempora cum, dolor neque tenetur nam doloremque odio dolorum! Consequuntur molestiae nobis deleniti nesciunt culpa.

CSS Container Queries support
Logo of Chrome Logo of Firefox Logo of Safari
105 110 16

But wait, there’s more!

With Media queries, we can query not just sizes

@media (pointer: coarse) {
  ...
}
@media (prefers-reduced-motion: reduce) {
  ...
}

What about Container queries?

Actually…

According to the spec, we should be able to do this:

@container style(background: white) {
  header { color: #222; }
}
A marker circle around '100vw'
Vintage picture of a surprised child

… but we can’t.

(For now.)
A sad boy looking out of a window with rain drops

But!

@container style(--look: featured) { ... }
A marker circle around 'style(--look: featured)'

It’s ok for custom properties!

.card-container {
  container-name: card;
  /* No need to declare container-type!
     Every element is a style container */
}Brush underline under 'no need'
@container card style(--look: featured) {
  .card {
    background: salmon;
  }
}

… don't we have classes for this?

Clip of a confused Oliver Hardy
.card-container.featured .card {
  background: salmon;
}

A couple of reasons

1. Reusability

We have loose control on what style are applied to the parent, but we want to react to them.

The goal is avoid messing up the overall result. This applies to style queries in general, but custom properties are good for predefined appearances.

2. Inheritance

Custom properties are inherited, classes are not. Selecting descendants is problematic.

3. Web Components

Custom properties are inherited and thus get through the Shadow DOM's style encapsulation.

We don't have ::theme() yet and forwarding parts is cumbersome, so this can be a way to set predetermined styles in the root, and let all the custom elements deep in the Shadow DOM chain read it.

4. Readability

Properties have explicit meaning, so it should be clearer what we're querying for.

This makes more sense when style queries support will be complete.
CSS Container Style Queries support
Logo of Chrome Logo of Firefox Logo of Safari
111 - -

Notable ideas

@container style(--theme: dark) {
  p { ... }
}
@container style(--theme: rainbows) {
  header { ... }
}
Because one thing is the theme set as preferred, another is the theme set by the user. This is especially useful for encapsulated styles.

Notable ideas

@container style(--content: minimal) {
  .abstract { display: none; }
}
@container style(--content: verbose) {
  .details { display: block; }
}

Notable ideas

@container style(--spacing: loose) {
  main { padding: 2rem; }
}
@container style(--spacing: compact) {
  main { padding: 0.5rem; }
}

Notable ideas

@container style(--orientation: vertical) {
  section { flex-direction: column; }
}
@container style(--orientation: auto)
  and (width < 10rem)
  { ... }
You can combine size queries and style queries, no problem!

But even more has to come…

.bar {
  width: var(--progress-value);
  background: red;
}
@container style(--progress-value >= 50%) {
  .bar { background: yellow; }
}
@container style(--progress-value >= 90%) {
  .bar { background: green; }
}
A marker circle around 'style(--progress-value >= 50%)' A marker circle around 'style(--progress-value >= 90%)'
Logo of JavaScript

In the end…

Can I use them?

“Let’s ship it!”

Illustration of a sail ship at sea

It's clear that CQ, with their ability to set styles based on the containers, are going to be the Next Big Thing in layouts and styles. It's going to be even clearer when the style queries specification will be fully defined and implemented in all browsers.

Every widget that we used to design only as full-width components can now be rethought as adaptable functionalities that can fit every spot of our website.

Links

That's all, folks! Waving hand
@use 'conf.scss';
@each $question of conf.$questions {
  answer: $question;
}