A CSS container queries example
Tags: css, webdev, webdesign, todayilearned
Published: 2022-01-11 11:13:00

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](https://piccalil.li/blog/container-queries-are-actually-coming/), 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`).

```css
img {
  max-width: 100%;
  height: auto;
}
```

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"](https://beyondtellerrand.com/events/dusseldorf-2019/speakers/heydon-pickering) a layout using sophisticated CSS that will become more elegant and readable by using container queries.

{% vimeo https://vimeo.com/336148765 %}

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](https://heydonworks.com/article/the-flexbox-holy-albatross-reincarnated/).

### 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)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtgryrakkt6endskmyk3.png)](https://codepen.io/openmindculture/pen/xxXaLed)

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

```css
.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);
}
```

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](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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s8mg6z8qr39xmb3ueu5b.png)

## Refactoring the Albatross Flexbox Example

We **don't** have to use the [contain property](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Containment) **anymore (since 2022 use `container-type` instead!)** 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](https://dev.to/suprabhasupi/future-of-css-container-query-4ma4) explaines containment and container queries, providing a hands-on example.

To define a container that enables container queries based on width and height, we used the existing containment property `contain: size`, but since 2022, `container-type: size | inline-size | block-size` has become the preferred syntax.

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

Edit (August 2022): I have updated the code example below to reflect the recommended syntax, which is more intuitive anyway. For more information and other possible `container-type` values, see [CSS Container Query Syntax Update](https://dev.to/ingosteinke/css-container-query-syntax-update-5cg5).

```css
.container {
  container-type: inline-size; /* obsoletes old experimental contain: property */
  /* deprecated: contain: layout inline-size style; */
}

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

{% codepen https://codepen.io/openmindculture/pen/jOGvZNO %}

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](https://dev.opera.com/articles/new-structural-elements-in-html5/#how-decided) 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](https://tomquinonero.com/blog/a-guide-to-css-container-queries/) as a polyfill and switch browsers or feature flags to make sure that our code works as expected with or without container queries.

{% codepen https://codepen.io/openmindculture/pen/qBPMpQj %}