Jul 27, 2021

Getting Started with CSS Container Queries

For as long as I’ve been working full-time on the front-end, I’ve heard about the promise of container queries and their potential to solve the majority of our responsive web design needs. And, for as long as I’ve been working on the front-end, there has been a running joke that we’d never actually get them coupled with a fair amount of anguish over their absence from our front-end toolbox.

All that is starting to change. Seemingly out of nowhere, a draft spec for container queries became available in Chrome Canary, giving developers the opportunity to experiment with them in the browser and provide meaningful feedback to help advance the spec forward.

So, now that we have the ability to play with an initial implementation of container queries, let’s look at what they are, what problems they solve, and how we can use them in their current state.

Before we do that, let’s look at what we currently have available to us.

Media Queries

Media queries unlocked responsive web design, giving developers the ability to respond to the user’s browser viewport and adjust styles and layout accordingly. To use them, we set a base style in CSS, then set up a media query within which styles are adjusted when whatever condition the media query is testing for is met.

.wrapper {
   padding: 1em;
}
@media (min-width: 60em) {
   .wrapper {
     display: grid;
     grid-template-columns: repeat(4, 1fr);
     padding: 2em;
   }
}

More recently, media queries have evolved to allow developers to tailor styling based on a user’s system preferences for things like dark mode or reduced animation.

body {
  color: #44464a;
  background: white;
}
/*== invert colors if a user's system is set to dark mode ==*/
@media (prefers-color-scheme: dark) {
   body {
     color: white;
     background: #44464a;
   }  
}
          
.animation {
  animation: pulse 1s linear infinite both;
}
/*== remove or lessen the animation if a user's system is set to prefer reduced motion ==*/
@media (prefers-reduced-motion) {
   .animation {
      animation: none;
   }
}

Feature Queries

In recent years, feature queries have been added to all modern browsers, allowing us to test for browser support of various CSS properties and provide a suitable fallback for non-supporting browsers. Here, I’m testing support for the initial-letter property and applying styles for a dropcap if a browser supports it.

@supports (initial-letter: 4) or (-webkit-initial-letter: 4){
  .article::first-letter{
      font-weight: bold;
      margin-right: 0.5em;
      -webkit-initial-letter: 4 1;
      initial-letter: 4 1;
    }
}

What are container queries and what problems do they solve?

Container queries are an emerging browser feature that allow us to target elements based on the context of a containing element. They allow us to focus on the context of a component for our styling outside of the context of the viewport. This means we can drop a component anywhere and get the styling we expect.

It’s important to note the only children or descendants of an element designated as a container can have their styling affected by rules in a container query. This makes it possible for an element within a container to be a container itself. This also solved the recursive issue that plagued container queries, initially called element queries, where an element would query itself to apply styles.

The current state of container queries

Container queries are in an experimental draft implementation within Google Chrome Canary. The spec is a work in progress and is subject to change, so you shouldn’t start shipping them just yet.

However, the implementation means that we can start experimenting with the syntax by enabling a flag within Canary. By going to chrome://flags and enabling the container queries flag, we can get a feel for the current syntax.

Container queries flag enabled in Chrome Canary.

The syntax

As mentioned earlier in this post, container queries work on the children and descendants of the nearest element designated as a container. We do this by applying the contain property to the element we want to serve as our container. Here, I’ll apply it to an element with a card-wrapper__card class.

.card-wrapper__card {
   contain: layout inline-size style;
}

In this example, the layout value is creating a block formatting context which prevents the contents from affecting contents in another container. Meanwhile, the inline-size value is part of the spec authored by Miriam Suzanne, which creates a single axis containment context and allows us to begin experimenting with container queries.

Now that we have a container established, we can alter the styles of the children of that container as the container itself changes sizes.

/*=== some base styles ===*/
.card-wrapper__card svg {
  width: 60px;
  border: 1px solid lightblue;
  border-radius: 5px;
  fill: DodgerBlue;
  box-shadow: 3px 3px 0 pink;
  padding: 0.25em;
}
/*=== update based on container's width ===*/
@container (min-width: 300px) {
  .card-wrapper__inner {
    display: flex;
    gap: 16px;
    align-items: center;
  }
  .card-wrapper__card svg {
    width: 100px;
    flex: 1 0 100px;
    box-shadow: none;
    border: none;
  }
}

As you can see, the syntax for writing a container query is strikingly similar to what we’re used to with media queries. This alignment, should it continue, should make experienced CSS developers quite comfortable with using them. The above code produces the below result.

Here, we can see that each card depicting the daily weather is responsible for its own layout. As an aside, the overall page layout adjusts to the viewport in classic responsive behavior, but now the layout for each card is removed from the context of the viewport. This gives us immense control over more granular layout concerns.

A note of caution

As exciting as it is to finally see this in the browser, it’s worth noting that container queries are a long way from production ready. First, they are only enabled in Canary builds at the moment. Second, the current spec is a work in progress and is likely to change before it is finalized.

If you do decide to throw caution to the wind and start implementing container queries in your work, make sure to lean heavily on progressive enhancement. Using a combination of the feature queries mentioned earlier in the post and a layout that holds up without container queries, you could be relatively safe incorporating them into your work. Provided, of course, you’re not squeamish about an inevitable re-factor.

Still, after waiting so long to see this feature that developers have been begging for, it’s incredibly satisfying to finally see a working implementation, however fragile.

Where to go from here

As developers, the rough spec for container queries gives us an immense opportunity to leverage influence over the browser’s ultimate implementation. Download Chrome Canary, turn on the feature flag and start playing around. And, if you want to contribute to the process, there is an issue tracker on Github where you can contribute feedback and follow various issues.

Container queries are the future

CSS has come a long way over the last few years. From Grid to logical properties to the nascent approach to container queries, much of what the front-end landscape has needed for so long is finally available, or close to it. With this initial pass at container queries, developers have a unique opportunity to test drive a long sought after feature and contribute to its specification. Here’s hoping the pace of progress with CSS doesn’t let up and we see a stable version of container queries in all browsers within a short period of time.

About the Author

Matthew James profile.

Matthew James

Sr Consultant
Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Infrastructure as Code – The Wrong Way
You are probably familiar with the term “infrastructure as code”. It’s a great concept, and it’s gaining steam in the industry. Unfortunately, just as we had a lot to learn about how to write clean […]
Snowflake CI/CD using Jenkins and Schemachange
CI/CD and Management of Data Warehouses can be a serious challenge. In this blog you will learn how to setup CI/CD for Snowflake using Schemachange, Github, and Jenkins. For access to the code check out […]
How to get your pull requests approved more quickly
TL;DR The fewer reviews necessary, the quicker your PR gets approved. Code reviews serve an essential function on any software codebase. Done right, they help ensure correctness, reliability, and maintainability of code. On many teams, […]
Kafka & Kubernetes: Scaling Consumers
Kafka and Kubernetes (K8s) are a great match. Kafka has knobs to optimize throughput and Kubernetes scales to multiply that throughput. On the consumer side, there are a few ways to improve scalability. Resource & […]