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;
}
}
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>
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 {
container: 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 layout (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;
}
}
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.
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.
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 ❤️🧠🧠❤️🦄🦄🧠❤️🧠