DEV Community

Cover image for A CSS container queries example
Ingo Steinke
Ingo Steinke

Posted on • Updated on

A CSS container queries example

CSS container queries are similar to media queries, but related to a container element size rather than the viewport size. While adaptive layouts often set breakpoints based on the viewport using media queries, we can use container queries to achieve a similar effect when creating modular components in a design system.

But can we use Container Queries?

At the time of writing, in January 2022, container queries are only available after opt-in by feature flag, so don't expect container query support in your regular end-user's browsers today. But, like Andy Bell wrote, we can start to use container queries progressively right now:

If the browser doesn’t understand some CSS, it’ll ignore it and carry on parsing the rest, so we can effectively use container queries today.

What not to use Container Queries for

HTML websites are responsive out of the box. Without adding style rules, text content will adapt to fill the browser window so that it does not flow out of the visible area. Adding a few lines of CSS, we can make images behave the same (provided we set their width and height or an explicit aspect-ratio).

img {
  max-width: 100%;
  height: auto;
}
Enter fullscreen mode Exit fullscreen mode

Provided that we properly stated the actual (intrinsic) image sizes, we can apply this rule safely without any media query or container query. If the image is smaller than the viewport width, the rule will have no effect. On smaller screens, the browser can use the resulting aspect ratio to calculate the height and resize the image without distortion. And if we want to hide an images on mobile screens, we can use a picture elements with a srcset to prevent loading hidden images.

Use Cases for Container Queries

Maybe we want to toggle the flex-wrap or flex-direction property, set position: fixed with a z-index, or change typography and colors based on the available space for our component, depending on how much space is available for our component.

By taking into account a parent container rather than the whole site, we can design web components that can be reused inside other columns, dynamically changing their appearance based on the width or height that is actually available.

The "Flexbox Holy Albatross"

At beyond Tellerrand conference 2019, Heydon Pickering presented the "Holy Albatross" a layout using sophisticated CSS that will become more elegant and readable by using container queries.

The idea of emulating container queries using other CSS properties had become an ambition obsession like searching for the Holy Grail, impossible to avoid like the Albatross vendor in a sketch by Monty Python's Flying Circus, so he called his code the Flexbox Holy Albatross.

Emulating Container Queries in a Flexbox

In Heydon's example, a flexbox will automatically switch from horizontal (multi-column) to vertical (single column) flexbox layouts, by a calculating a flex-basis based on the difference between our breakpoint (640px in the below example) and the available container width (100%).

Codepen: Flexbox Albatross without Container Queries (screenshot)

This technique works pretty well, but the code is not easy to understand.

.container {
  display: flex;
  flex-wrap: wrap;
  --margin: 1rem;
  --modifier: calc(640px - 100%);
  margin: calc(var(--margin) * -1);
}

.container > * {
  flex-grow: 1;
  flex-basis: calc(var(--modifier) * 999);
  height: 20vh;
  margin: var(--margin);
}
Enter fullscreen mode Exit fullscreen mode

Let's refactor the code using container queries.

Using Container Queries

First, we have to make sure we can actually use them, which is currently an opt-in preview feature in Chrome and Chromium-based browsers like Edge or Vivaldi.

Navigate to chrome://flags, search for container, switch "Enable CSS Container Queries" to "Enabled" and restart your browser.

Screenshot: enable container queries in Chrome's feature flags

Refactoring the Albatross Flexbox Example

We have to use the contain property to explicitly define our container as a container element (similar to using position: relative to define a parent context for position: absolute).

@suprabhasupi's article Future of CSS - Container Query explaines containment and container queries, providing a hands-on example.

To define a container that enables container queries based on width and height, we can use the existing containment property contain: size.

In many common use cases, we are only interested in the width. This is what the new contain: inline-size is for. This common use-case also applies to our flexbox example.

In any case, we also need to define a containment for layout to enable container queries, as well as style to prevent dynamic style calculation causing infinite loops.

If you don't specify style, container queries will not work in the current experimental implementation (of late 2021 at least).

.container {
  contain: layout inline-size style;
}

@container (max-width: 640px) {
  .container > * {
    flex-basis: 100%;
  }
}
Enter fullscreen mode Exit fullscreen mode

If you see a pink border around the albatross boxes in the small-container vertical column layout, your browser has applied the styles based on CSS container queries.

Shipping Stable Code to Production

At the time of writing, no popular browser supports container queries by default. So what's the point in using future CSS right now?

Code Usage as Vote for a Feature

Code is crawled and examined by various parties like Web Almanac, search engines and browser vendors. This was how semantic HTML 5 elements like nav got their names and this might also be a hint for decisions on what features to prioritize and which ones to deprecate.

Citation needed: I overheard that there is still similar research going on to help decide which browser features to prioritize, but I did not find any official statement to acknowledge this claim.

Adding Fallback Code

We can add a container query emulation like Heydon's "Flexbox Holy Albatross" or use a container query polyfill as a polyfill and switch browsers or feature flags to make sure that our code works as expected with or without container queries.

Discussion (0)