A first look at CQFill, a Polyfill for CSS Container Queries

Jonathan Neal just announced that he has been working on a polyfill for CSS Container Queries. Let’s take a look at how it works …

🤔 Container Queries?

Container Queries allow authors to style elements according to the size of a container. This is similar to a @media query, except that it evaluates against a container instead of the viewport.

~

Unfortunately the polyfill is not a simple drop-in that will work with your existing CSS code. This is because rendering engines that don’t support Container Queries will discard those specific statements and declarations.

To work around this, the polyfill requires you to duplicate some CSS with an alternative syntax.

  1. Duplicate the value for the contain property into a CSS Custom Property named --css-contain
  2. Duplicate the @container rule as an @media rule bearing the text --css-container

Like so:

/* Create a Container Root */
.container {
  contain: layout inline-size; /* For browsers that support Container Queries */
  --css-contain: layout inline-size; /* For the polyfill to use */
}
/* Container Query */
@container (min-width: 700px) { /* For browsers that support Container Queries */
  .contained {
    /* … */
  }
}

@media --css-container and (min-width: 700px) { /* For the polyfill to use */
  .contained {
    /* … */
  }
}

As those duplicated rules are valid CSS, browsers won’t discard them and the polyfill can pick them up 🙂

⚠️ It’s very import to use the naming as used in the code above. The Custom Property must be named --css-contain and the Media Query must contain the text --css-container. If named differently, the polyfill won’t be able to pick them up.

~

Once your styles have been declared you can import the polyfill and call it:

import { cqfill } from "https://cdn.skypack.dev/cqfill";

cqfill();

If you want a local copy of CQFill, you can install it per NPM/Yarn.

npm install cqfill

☝️ When using Next.js or PostCSS you don’t even need to call the polyfill, as the CQFill repo includes plugins for those.

~

Here’s my original demo, adjusted to include the polyfill:

See the Pen CSS Container Queries Demo (with Polyfill) by Bramus (@bramus) on CodePen.

Great work Jonathan, works like a charm!

CQFill: CSS Container Queries Polyfill (GitHub) →

~

🔥 Like what you see? Want to stay in the loop? Here's how:

Container Queries are Actually Coming / Say Hello To CSS Container Queries

In addition to my first look + demo at Container Queries, both Andy Bell and Ahmad Shadeed have also published posts covering them.

~

Ahmad starts off with explaining the idea behind them, before digging into a ton of use-cases. I especially like the pagination use-case, something I hadn’t thought of yet myself.

~

In his post, Andy taps into a — not yet existentcw unit, where 1cw equals 1% of the container. This comes in handy for tweaking the font-size based on the available space.

/* Before */
h1 {
  font-size: clamp(
    var(--fluid-type-min, 1rem),
    calc(1rem + var(--fluid-type-target, 3vw)),
    var(--fluid-type-max, 1.3rem)
  );
}

/* After */
h1 {
  font-size: clamp(
    var(--fluid-type-min, 1rem),
    calc(1rem + var(--fluid-type-target, 5cw)),
    var(--fluid-type-max, 1.3rem)
  );
}

Yes, we totally need this type of unit!

~

Container Queries are Actually Coming (by Andy) →
Say Hello To CSS Container Queries (by Ahmad) →

CSS Container Queries: A First Look + Demo

Update 2021.04.27: Jonathan Neal has created a Polyfill for Container Queries. Check out an updated demo + instructions how to use here.

Back in November 2020 it was announced that Chromium would experiment with Container Queries — back then just a proposal but earlier this year (February 2021) adopted to become part of the CSS Containment Module Level 3 Specification.

Just before the weekend a first version of this experimental implementation landed in Chromium Canary for us to play with (behind a flag). Let’s take it for a test drive …

👨‍🔬 The CSS features described in this post are still experimental and not finalized at all! If you’re feeling adventurous you can play with these new features today, but you’ll need at least Chromium 91.0.4459.0 with the #enable-container-queries flag enabled through chrome://flags.

~

Wanting to test Container Queries out I quickly threw a demo together using a classic card component. By default our component shows and image on top and a description below that. If enough space becomes available, they will be shown next to each other. Should even more space become available, then the image will grow even more.

In the recording below you can see the different layouts we want to achieve:

~

The markup for all those cards is the same and is pretty straightforward. Only extra thing I’ve added is an extra wrapper div .animalcard-wrapper so that our container queries will play nice when being used inside CSS Grid

<div class="animalcard-wrapper">
	<div class="animalcard">
		<div class="animalcard__image">
			…
		</div>
		<div class="animalcard__description">
			…
		</div>
	</div>
</div>

The default layout of our card uses CSS Grid to position the image and the description:

/* SMALL LAYOUT: Image stacked on top of Description */
.animalcard {
	display: grid;
	grid-template: "image" "description" / 1fr;
	gap: 1em;
	padding: 1em;
}

To be able to use Container Queries, we first need to create a Containment Context (Container Root) on the .animalcard-wrapper. We instruct the browser to keep track of the inline-size, which translates to the width, as we will be changing the layout of its children based on that dimension.

/* Container Queries: Create Container Root */
.animalcard-wrapper {
	contain: layout inline-size;
}

With this Container Root in place, we can now add extra styles to apply when the Container Root reaches a certain width

/* MEDIUM LAYOUT: Image next to Description (1fr each) */
@container (min-width: 30rem) {
	.animalcard {
		gap: 2em;
		padding: 2em;
		grid-template: "image description" / 1fr 1fr;
	}

	.animalcard__description {
		text-align: left;
	}
}

/* LARGE LAYOUT: Large Image next to Description */
@container (min-width: 70rem) {
	.animalcard {
		grid-template-columns: 2fr 1fr;
	}
}

~

All together our demo finally becomes this:

See the Pen CSS Container Queries Demo by Bramus (@bramus) on CodePen.

😊

☝️ If you’re looking for more demos, Miriam Suzanne is collecting a bunch in this CodePen Collection. Be sure to check out Una‘s Episode Card for The CSS Podcast

~

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

The Raven Technique: One Step Closer to Container Queries

Building further upon The Holy Albatross technique, comes The Raven Technique by Mathias Hülsbusch:

I want to get closer to actual container queries! So, what does CSS have offer that I could tap into? I have a mathematical background, so functions like calc(), min(), max() and clamp() are things I like and understand.

Next step: build a container-query-like solution with them.

Leveraging clamp() he builds new CSS Custom Properties (aka CSS Variables) which in their turn are used as Conditions for CSS calculations.

☝️ Did you know Chromium will be experimenting with native Container Queries, and we might eventually have them built into the browser?

You can play with the results in the pen below, by adjusting the width of .try_out_dimensions although I’d recommend to read the explanatory post first 😉

The Raven Technique: One Step Closer to Container Queries →

Container Queries are coming to Chromium!

Update 2021-02-12: Thanks to the hard work by Miriam Suzanne and others this proposal is now officially part of the CSS Specification Process (ref) and set to be part of css-contain-3 … it’s happening, people! 🎉

Update 2021-03-28: A first iteration of this implementation has landed in Chrome 91 … let’s take a closer look and build a demo!

Just announced on the Chromium mailing list is an “Intent to Prototype” Container Queries, which is quite exciting news I must say!

🤔 Container Queries?

Container Queries allow authors to style elements according to the size of a container. This is similar to a @media query, except that it evaluates against a container instead of the viewport.

The experimental implementation will follow Miriam Suzanne’s proposal, which looks like this:

/* (1) Create an implicit "container root" */
main,
aside {
  contain: size;
}

.media-object {
  display: grid;
  gap: 1em;
}

/* (2) Container Query targeting the nearest 
   "container root" ancestor. The rules nested
   inside will only be applied if the "container
   root" has a max-width of 45em */
@container (max-width: 45em) {
  .media-object {
    grid-template: 'img content' auto / auto 1fr;
  }
}

Applying contain: size; (1) onto an element will make it an implicit “container root” or “containment context”. Elements contained inside it can then have container queries applied onto them, by use of a new at-rule @container (<container-media-query>) (2). The target selector and CSS rules to apply in that case are — similar to what we do with “regular” media queries — nested within the @container at-rule.

In the example above extra rules will be applied to .media-object whenever its nearest “container root” ancestor — such as <main> or <aside> — has a max-width of 45em.

🧑‍🔬 This proposal is experimental and has not been approved by the CSSWG yet. The expressed “intent to prototype” is meant as an experiment to see whether this idea would be worth pursuing or not. In the end, it could be that the final syntax can differ from the one listed here, if the proposal is workable in the first place.

~

A previous version of this proposal by L. David Baron required a context selector to be set, but that has been dropped here. The @container rule from Miriam’s version will work in any containment context (read: the nearest parent element that has contain: size set). The syntax might still change, but that’s irrelevant to the prototype which is to be implemented:

This is not at all finalized, but the underlying problems we need to solve in Blink are (mostly) the same regardless of how the feature is accessed, so we’ll for now use this proposal as the temporary syntax.

~

Intent to Prototype: Container Queries →
Chrome Tracking Bug →

🔥 Like what you see? Want to stay in the loop? Here's how:

Container Queries with the <watched-box> Custom Element

Heydon Pickering has created <watched-box>:

I wanted a simple, declarative container queries solution, and here it is:

  • ❤ Custom Element + ResizeObserver
  • 🥣 Use and mix together any CSS length units
  • 🖼 Orientation supported
  • 🧚‍♀️ ≅1.5KB minified

Once imported you can use it as follows:

<watched-box widthBreaks="70ch, 900px" heightBreaks="50vh, 60em">
  <!-- HTML and text stuff here -->
</watched-box>

<watched-box> will then automatically add the proper classes:

  • Less than or equal to the supplied width: w-lte-[the width]
  • Greater than the supplied width: w-gt-[the width]
  • Less than or equal to the supplied height: h-lte-[the height]
  • Greater than the supplied height: h-gt-[the height]

<watched-box>