Skip to main content

On container queries.

Over the last few years, a number of web designers, web developers, and agencies have been asking for “container queries,” saying they’d be a welcome addition to a responsive designer’s toolkit.

I think they’re right. And I’d like to add my voice to theirs.


So, right, okay: what are container queries? And why should we care about them?

Maybe I’ll start here: in the last few years, my design work has focused much more on patterns, and less on “pages.” Instead of treating a responsive design as a holistic, unified thing, where every part of the layout changes and adapts at the same rate, it’s more helpful to break a responsive layout down into smaller, reusable bits of design, including things like “masthead,” “footer,” “image caption,” and so on.

In other words, my design process involves looking at a responsive design as a network of small layout systems. Each of those components are basically little responsive designs themselves, with their own sets of breakpoints.

Here’s one example from a project I worked on, the responsive redesign of The Toast—specifically, the masthead.

If you can see the video, you may have noticed the layout goes through three big changes:

  1. A narrow, small screen-friendly masthead, containing the logo and an icon (which toggles the search bar);
  2. A mid-range layout, with the logo and search bar on opposite sides of the masthead; and then
  3. The widescreen masthead, with the search bar appearing opposite some social icons, and the logo “pulled” down into the page.

There are a few minor breakpoints that tweak some tiny details, but that’s basically it: three major layout changes, three breakpoints.

Now, this particular part of the design—this pattern—is more complex, and adapts more frequently, than most other patterns on The Toast’s site. An article headline might change its font size once or twice as the page resizes; a certain type of link looks the same on the smallest screen as it does on the widest. By understanding how these little layout systems work, I can stitch them together to build a larger, responsive layout system—a responsive “page,” if y’like.

But each of those patterns, including our masthead, changes based on the needs of the content inside it. Generally, more complex patterns will have more breakpoints, while simpler patterns have fewer. (If they have any breakpoints at all.) And those breakpoints are defined by a @media query, which says “when the browser’s viewport exceeds this width or height, let’s change the design.”

But what happens if a component doesn’t match the width of the viewport?


The Toast’s website has a fair number of recirculation modules, which promote content pulled from their archives. Thing is, these lists can appear in different parts of the design: in the main river of content on a homepage, embedded in articles, or in the sidebar that appears on wider screens.

Here’s one of the more complex recirculation modules, which can appear in the main content well or in the sidebar—depending on the width of the design:

If you can see the video, you might have noticed a shift at the end—why does the module get so tiny? By default, this recirculation block sits in the main content well. But given the importance of its content, we decided we wanted to make it more visible on wider screens. To that end, we’re using a little JavaScript to pluck the list out of its default position and—when there’s enough room to do so—drop it into the sidebar. This selective promotion of content is something I discussed in my second book; it’s a great way to make key items more (or less) prominent as your responsive design changes shape.

But let’s put the technical foofaraw aside for a minute, and review what’s happening to the layout of our little module:

  1. By default, the list of links appears as a single column layout on small screens.
  2. As the screen gets wider, it moves to a two-column layout.
  3. We hit a three-column layout at the middle range.
  4. But then, once we reach the widescreen layout, the list moves into the right-hand sidebar. Once that happens, the list reverts to a two-column layout.

The TL;DR version? Our module’s layout shifts between one-, two-, and three-column layouts as the design gets wider…but then it shifts back to a two-column layout on the widest screens.

In the CSS, here’s roughly how that’s done:


/* Two-column layout */
@media (min-width: 31.25em) {
    .ranked-list li,
    .ranked-list li:nth-child( n ) { … }
    .ranked-list li:nth-child( 2n ) { … }
    .ranked-list li:nth-child( 2n+1 ) { … }
}
/* Three-column layout */
@media (min-width: 40em) {
    .ranked-list li,
    .ranked-list li:nth-child( n ) { … }
    .ranked-list li:nth-child( 3n ) { … }
    .ranked-list li:nth-child( 3n+1 ) { … }
}
/* Revert to the two-column layout in the sidebar */
@media (min-width: 60em) {
    .recirc-side .ranked-list li,
    .recirc-side .ranked-list li:nth-child( n ) { … }
    .recirc-side .ranked-list li:nth-child( 2n ) { … }
    .recirc-side .ranked-list li:nth-child( 2n+1 ) { … }
}

Outside the media queries, we’ve got our single column layout. As our breakpoints get wider, we move to two- and three-column layouts, thanks to a little :nth-child() work. But once we’re above the 60em breakpoint, there’re some new rules to revert to our two-column layout if the list appears inside the .recirc-side block—that is, if our JavaScript successfully moves the module to its new home in the sidebar.

There are, of course, other ways you could implement this. We could reorganize our code a bit, and consolidate all the two-column layouts—small- and widescreen—in the first media query, and let higher specificity override the three-column breakpoint:


/* Two-column layout on smaller screens, and again on wider screens (when we’re in the sidebar) */
@media (min-width: 31.25em) {
    .ranked-list li,
    .recirc-side .ranked-list li,
    .ranked-list li:nth-child( n ),
    .recirc-side .ranked-list li:nth-child( n ) { … }
    .ranked-list li:nth-child( 2n ),
    .recirc-side .ranked-list li:nth-child( 2n ) { … }
    .ranked-list li:nth-child( 2n+1 ),
    .recirc-side .ranked-list li:nth-child( 2n+1 ) { … }
}
/* Three-column layout */
@media (min-width: 40em) {
    .ranked-list li,
    .ranked-list li:nth-child( n ) { … }
    .ranked-list li:nth-child( 3n ) { … }
    .ranked-list li:nth-child( 3n+1 ) { … }
}

(Either way: hurk.)

Additionally, there are technical solutions you could work in here: perhaps you’re using Sass, so you could use a mixin to “scope” some of these styles. Newer layout methods like flexbox or grid would mitigate some of the column management I’m doing. Or maybe you’d use JavaScript to restructure the list differently, once it’s in the sidebar. The sky is, as the kids say, the limit!

The technical details are, ultimately, irrelevant. The fundamental fragility with this approach is that we’re relying on media queries to determine the design of our modules. In other words, I’ve written some code that’s saying, “Once the screen is this size and the element appears in a different, smaller container, use a narrower layout on this element.”

But, well, that’s weird. Why can’t we apply styles based on the space available to the module we’re designing, rather than looking at the shape of the viewport?


This is, in a nutshell, the disconnect that container queries are trying to address. As our designs become more modular and pattern-driven, the value of media queries has decreased. That’s not to say media queries are, like, bad—not at all. After all, they’re the best tool we’ve got right now. But there’s a divide growing between what our responsive designs need to do, and the tools CSS gives us to meet those needs. We’re making design decisions at smaller and smaller levels, but our code asks us to bind those decisions to a larger, often-irrelevant abstraction of a “page.”

Instead, container queries would allow responsive designers to change the display of a module based on the size of that module’s container. For our little recirculation module, container query-driven code might look something like this:

.recirc-container:(min-width: 20em) {
    .ranked-list li,
    .ranked-list li:nth-child( n ) { … }
    .ranked-list li:nth-child( 2n ) { … }
    .ranked-list li:nth-child( 2n+1 ) { … }
}
.recirc-container:(min-width: 40em) {
    .ranked-list li,
    .ranked-list li:nth-child( n ) { … }
    .ranked-list li:nth-child( 3n ) { … }
    .ranked-list li:nth-child( 3n+1 ) { … }
}

Container queries are, well, querying the amount of space allotted to an element. Rather than checking to see if a page is wider than 60em, and applying a two-column layout to an element because we just know it’ll need to be in a smaller sidebar, our container queries check to see how wide an element’s container is, and apply rules to ensure it’ll fit. They let us break free of media queries, and refocus our design on what we’re actually designing: the module itself.

As a result, our code doesn’t need to plan for weird layout exceptions. Hypothetically, container queries would help our patterns live anywhere in a responsive layout, making our patterns considerably more robust, and significantly more reusable.


Just to be clear: container queries, as a thing, do not exist. The syntax I used above? Totally, utterly, completely fake. There are a number of innovative JavaScript libraries available online that simulate how container queries might work, as well and even a few community-written specifications. But absent a clear, formal, browser vendor-approved standard for how container queries might work, I only use those libraries for layout experiments, not production websites.

Is anyone working on standardizing container queries? Well, I’m not sure—but I don’t think there’s much movement. The Responsive Issues Community Group (RICG), the community-led working group that brought us the responsive images specification, identified container queries as their next priority. In fact, Mat Marquis, chair of the RICG, wrote an excellent article covering container queries: their background, their status, and how the community can get involved.

Beyond that, I don’t know if work has, in fact, been ongoing. I gather browser vendors are spending more time on various JavaScript APIs that would allow developers to, well, hack container query-esque behaviors into their websites. Houdini seems to have the most weight behind it right now, as it’s an API that’d expose more of a browser’s underpinnings to web developers: if you ever wanted to write your own container queries engine—or, heck, write your own styling engine—Houdini would give you the tools to do just that.

While I can respect that approach—“build a better API, and let a thousand container query libraries bloom”—there’s a clear and immediate need in the design community for a CSS-driven solution to this problem. The need for container queries, or something like it, has come up on every responsive project I’ve worked on since helping launch The Boston Globe. And it’s not just me: in fact, I’m one of the very last folks to chime in on this issue. There’s an incredible clamor for container queries, with folks from every corner of the responsive community asking for something that solves this problem. So personally, I’d love to see at least one browser vendor partner with the RICG, and get properly fired up about this.

I don’t want to suggest, mind, that media queries are dead. But as Scott Jehl once quipped, “If CSS element queries existed, I would have nearly zero uses for CSS media queries.” Now, I don’t know about zero, myself—but I can say with some certainty that most queries I’d write would be container-based. But heck, even if container queries landed today, but I could still see myself writing a number of media-focused queries in my design: perhaps optimizing for the shape of the display, its color density, or even just coordinating global typography changes.

And finally, I don’t want to suggest that the technical challenges of specifying container queries are in any way easy. But some kind of movement would be deeply appreciated by the entire responsive design community. Speaking just for myself, I know container queries would revolutionize my design practice, and better prepare responsive design for mobile, desktop, tablet—and whatever’s coming next.

Current page