DEV Community

Cover image for CSS Container Queries
Andrew Bone
Andrew Bone

Posted on

CSS Container Queries

Something new, and exciting, is coming to CSS and when I say 'is coming' I mean it's not supported in any browsers yet and the spec is not finalised (at the time of writing). That all being said it's behind a flag in the next version of chrome and I have no doubt will be in all 'modern' browsers in no time.

What are container queries

Container queries are similar to media queries but with one major, and crucial, difference. Media queries query the entire document and are used to modify content depending on those queries. For instance if the document is over 1025px you may want to move content in two columns rather than one. This would look something like this.

main.content {
  column-count: 1;
  column-gap: 2em;
}

@media screen and (min-width: 1025px) {
  main.content {
    column-count: 2;
  }
}
Enter fullscreen mode Exit fullscreen mode

Container queries follow the same principle but rather than querying the entire document they, instead, query the container.

How do they help developers

Imagine the following scenario; you've got a contact card you want to display all over your site. In some places it's in the main content but in other places you've decided to display it in an aside. On the same media query the aside could be 250px but the main section could be 700px leading to the cards needing to look different. The solution is easy enough you need to have different classes for the cards with different media queries but there is a better way... Container queries!

How do you use container queries

To use container queries we have to tell the container (the parent of the element we want to apply the query to) that we care about its dimensions, we do this with the new contain property.

none
Indicates the element renders as normal, with no containment applied.
strict
Indicates that all containment rules except style are applied to the element. This is equivalent to contain: size layout paint.
content
Indicates that all containment rules except size and style are applied to the element. This is equivalent to contain: layout paint.
size
Indicates that the element can be sized without the need to examine its descendants' sizes.
layout
Indicates that nothing outside the element may affect its internal layout and vice versa.
style
Indicates that, for properties that can have effects on more than just an element and its descendants, those effects don't escape the containing element. Note that this value is marked "at-risk" in the spec and may not be supported everywhere.
paint
Indicates that descendants of the element don't display outside its bounds. If the containing box is offscreen, the browser does not need to paint its contained elements — these must also be offscreen as they are contained completely by that box. And if a descendant overflows the containing element's bounds, then that descendant will be clipped to the containing element's border-box.

The documentation is a little lacking on Mozilla at the moment, which is rare. We want to use the inline-size property which is described on Mozilla elsewhere as

When we use media queries, most of the time we care about the available width (or inline-size).

Practical examples

Let's take our contact card example from earlier and come up with some code to describe it.

<div class="site">
  <main class="content">
    <div class="contact-card">
      <img class="contact-card__profile-image" src="profile.png" alt="profile" />
      <div class="contact-card__profile-information">
        <h1>Both Names</h1>
        <p>Some info about me</p>
      </div>
    </div>
  </main>
  <aside class="side-panel">
    <div class="contact-card">
      <img class="contact-card__profile-image" src="profile.png" alt="profile" />
      <div class="contact-card__profile-information">
        <h1>Both Names</h1>
        <p>Some info about me</p>
      </div>
    </div>
  </aside>
</div>

Enter fullscreen mode Exit fullscreen mode

The HTML is quite simplistic but I think it gets the point across we have a contact card, its in two places with, potentially, drastically different widths.

/* Just some simple css to get it started */
.site {
  display: flex;
  max-width: 800px;
  margin: 0 auto;
}

main.content {
  width: 60%;
  background: #ccc;
}

aside.side-panel {
  width: 40%;
  background: tomato;
}

/* Real css starts here */
main.content, aside.side-panel {
  contain: layout inline-size;
}

.contact-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 200px;
  background-color: white;
  padding: 2em;
  box-sizing: border-box;
  border-radius: 2px;
  margin: 1em;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 1px 1px rgba(0, 0, 0, 0.4)
}

.contact-card__profile-image {
  height: 50px;
  width: 50px;
  border-radius: 50px;
  border: 1px solid black;
}

.contact-card__profile-information {
  margin-left: 0.5em;
}

.contact-card__profile-information h1 {
  text-align: center;
  margin: 0;
  font-size: 1.2em;
}

.contact-card__profile-information p {
  text-align: center;
  margin: 0.5em 0 0 0;
}

@container (min-width: 450px) {
  .contact-card {
    width: 300px;
    flex-direction: row;
    align-items: flex-start;
  }

  .contact-card__profile-information h1 {
    text-align: left;
  }

  .contact-card__profile-information p {
    text-align: left;
  }
}
Enter fullscreen mode Exit fullscreen mode

In this CSS we style the contact-card and then we have a container query that changes the style of the card when we pass a width of 450px. As you can see it's basically the same as a media query but is based on the container.

Here is how the code will render (hopefully we can try it in more browsers one day soon). Here's the code if for when it actually works, jsfiddle.

example

Influence the spec

As I said right at the start the spec isn't yet finalised, if you want to look at what people are suggesting or if you want to make a suggestion yourself there is still time to do it. Head over to the git issues board and have a look.

The end

I'm very excited about this, I work mostly with React and I am really looking forward to components being able to change based on their parent's size.

A very exciting time

Well that's it, that's the post. If you have any questions feel free to post them in comments I might not be able to answer them off the top of my head but let's learn together. You can come find me on Twitter if you like.

Thank you so much for reading ❤️🧠🧠❤️🦄🦄🧠❤️🧠

Top comments (12)

Collapse
 
grahamthedev profile image
GrahamTheDev

This really is the thing I am looking forward to the most in CSS.

Put it like this, I have already written a mini poly fill that I am using for a new site I am building.

I think the big problem is going to be older browsers as from what I have seen the “fall back” is hard to do gracefully, so you either have to go mobile first and put up with a crap design on desktops or design everything with careful flex designs that are kind of responsive in the first place and enhance it with container queries.

Be interesting to see what pattern people settle on when this gets released as until we can physically play with it it is hard to know what gotchyas actually exist!

Collapse
 
link2twenty profile image
Andrew Bone

In theory IE will be the only hold out and if that's the case we can almost ignore the issues. 😅

Collapse
 
grahamthedev profile image
GrahamTheDev

That is why it will be interesting to see what happens as as long as it displays reasonably well and is usable on IE I am happy.

Unlike most devs I still support IE9 due to accessibility as that is the realm I work in. However whenever I say that people confuse support with pixel perfection so as long as the pattern fallback allows it to be usable and accessible I am happy enough.

Thread Thread
 
link2twenty profile image
Andrew Bone

Where I work we "support" IE11 but it's the same as you if it doesn't break and still makes sense to the end user that's good enough.

Thread Thread
 
grahamthedev profile image
GrahamTheDev

I also have a rule that I can spam polyfills for IE with conditionals, at that stage it normally isn’t as much of a headache as it used to be.

Collapse
 
manlikecliff profile image
ManLikeCliff

IE and it's wahala. My last resort.

Collapse
 
billraymond profile image
Bill Raymond

Thanks for this great article and also one of my favorite scenes from The Matrix :-)

Sometimes I am working with CSS Grids and I would like to draw a box around them, mostly for testing purposes. Using a code sample from the LayoutIt Grid, I can draw a red box around the grid container, like this:

.grid-container * {
  border: 1px solid red;
  position: relative;
}

.grid-container *:after {
  content:attr(class);
  position: absolute;
  top: 0;
  left: 0;
}
Enter fullscreen mode Exit fullscreen mode

Unfortunately, that method draws a box around the grid and any items contained within (like an image or an href for example). Could I use a CSS Container query to draw a box only around a grid? Or maybe only around grids contained within a certain grid? I'm not necessarily looking for you to provide the code (although that would be welcome), but more to understand if that is an approach I can use.

Thanks again!

Collapse
 
link2twenty profile image
Andrew Bone

Unfortunately it can't really help with that but dev tools (in both chrome and firefox) have great grid inspection support.

developer.chrome.com/docs/devtools...
developer.mozilla.org/en-US/docs/T...

Collapse
 
billraymond profile image
Bill Raymond

That is too bad. I have used the grid dev tools but was hoping there would be a better option to highlight items without having to go into inspection tools. Thank you for the response and for the great article! I had not realized how important this will be until your simple explanation!

Collapse
 
peterlunch profile image
Peter

Awesome post Andrew, now I want to experiment with these.

Collapse
 
naheem3410 profile image
naheem3410

The feature will further ease styling with CSS

Collapse
 
link2twenty profile image
Andrew Bone

It really will, less CSS will need to be written and that can only be a good thing 😊