Today’s web is built around components and that’s where media queries are lacking behind. We are going to see why in this article. But first, let’s cover the basics and start with a recap of media queries and the newer feature called container queries. Later we’ll jump into the benefits of container queries and when to use them or stick to the good old media queries.
Recap – What are Media Queries
Media queries are a CSS specification introduced with CSS3. The main idea behind media queries is to apply styles to an element based on the user agent or device the element is displayed. Common possible query values include but not limited to are: device type, orientation, and viewport [1].
1 2 3 |
@media screen and (min-width: 576px) and (orientation: landscape) { /* … */ } |
Example
Let’s say we have three divs of different sizes and we want to change their color for each of our three breakpoints (small: 576px, medium: 640px, large: 768px). The following code would do the trick.
Klicken Sie auf den unteren Button, um den Inhalt von codepen.io zu laden.
*resize the browser window
What are Container Queries
Container queries is a CSS specification introduced in late 2022. The main idea behind container queries is to apply styles to an element based on the size of the element’s container rather than the size of the viewport. You can listen to the properties and features of a container element. You can query the width but also custom properties [2].
Example
If we continue our example from the media queries recap section the only thing we need to change to turn the media query into a container query is to exchange @media with @container and add the line container-type: inline-size to the container class. The code now looks as follows:
Klicken Sie auf den unteren Button, um den Inhalt von codepen.io zu laden.
*in the bottom right corner you can resize the div
As already mentioned container queries are based on the width of the element they are applied on rather than the viewport, so what happens is that all three divs now change their background color independently (according to their own width) even though we apply the same queries to all of them.
Container Types
As already mentioned, there are 2 different container types.
inline-size sets the size limit only on the inline axis. This means that the width or inline-size can be queried.
As a block-size option could not be implemented by the browsers, it does not exist. The alternative is the size option.
With the size option, the size restriction is defined on both dimensions. This means that the height, orientation, or aspect-ratio can also be queried.
However, it should be noted that side effects can occur with the size option. So be careful using this option.
Container Name
If you have several nested containers or simply want to ensure that your query uses the desired container, a container can be given a name to query it specifically.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
.page { container-type: inline-size; container-name: page; width: 50%; display: flex; flex-direction: column; gap: 10px; } main { container-type: inline-size; container-name: main; display: grid; gap: 10px; } aside, section, footer { padding: 20px; } aside, footer { color: white; background-color: black; } section { background-color: grey; height: 150px; } aside { display: flex; justify-content: space-evenly; } /* The query watches the width of the 'page' container */ @container page (min-width: 450px) { main { grid-template-columns: auto 1fr; } aside { flex-direction: column; align-items: center; } } /* The query watches the width of the 'main' container (aside + content) */ @container main (min-width: 450px) { aside { background-color: orange; } } |
When a container query is added, the nearest ancestor container is searched for by default. By adding a name, a specific container can be targeted.
It’s also possible to use a short version to describe the type and the name of a container.
1 2 3 4 |
main { container: main; / inline-size; // container-name: main; container-type: inline-size container: main; // container-name: main; container-type: normal; } |
Container Query Units
Container Queries come with their own units that work like the already-known new viewport units introduced in 2022: 75svw = 75cqw [3][4]
Example:
Klicken Sie auf den unteren Button, um den Inhalt von codepen.io zu laden.
The key difference is, that the container query units are not relative to the viewport as long as they are inside a size container.
Example:
Overview about container query units:
unit | explanation |
1cqi | 1% of a query container’s inline size |
1cqb | 1% of a query container’s block size |
1cqh | 1% of a query container’s height |
1cqw | 1% of a query container’s width |
cqmin | The smaller value of cqi or cqb |
cqmax | The larger value of cqi or cqb |
Media Queries vs. Container Queries
We have now gained an overview of how and when media queries and container queries can be used in simple examples. Now let’s look at one more example that is closer to the real world. So let’s jump right in.
- real world example with explanation (media vs container)
Klicken Sie auf den unteren Button, um den Inhalt von codepen.io zu laden.
Key takeaways
@media | @container | |
size | always refers to the width and height of the viewport | always refers to the width and height of the selected container’s content box |
portability | most likely to break if you move the affected element to a different position | can be used at any position on the page |
use case | layout changes | component-based changes |
syntax | predefined syntax e.g. @media (min-width: 480px) {} |
same syntax available with increased feature set e.g. logical operators @container (width <= 480px) {} |
units | viewport units e.g. vh, vw | container units e.g. cqh, cqw |