Week 9: Container Queries
Agenda
- Zoom Tutorial
- Container Queries Basics
- In-Class
- Container Queries continued...
- Complete Project 1 - Two Page Website by Sunday
# Introduction to Container Queries
The @container
query is an evolution on @media
. As we've learned, @media
allows us to apply new styles based on the size of our viewport. Meaning we can set sizes for small screens, large screens and everything in between. What @container
allows us to do is set different styles based on the size of an element that is an ancestor of the element we want to apply styles to.
For example, consider this html structure:
<section class="posts">
<div class="container">
<h2>More Posts</h2>
<ul class="posts__list grid">
<li class="col">
<a href="#" class="card">
<div class="card__img">
<img
src="https://placedog.net/550/550?random"
alt="A random dog!"
/>
</div>
<div class="card__content">
<h3 class="card__title">Card Title</h3>
<p class="card__text">
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</p>
<span class="btn">Learn More</span>
</div>
</a>
</li>
</ul>
</div>
</section>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
If I wanted to use a container query to modify the styles applied to <a href="#" class="card">
, I could use any of the following elements as a reference for the container:
<section class="posts">
<div class="container">
<ul class="posts__list grid">
<li class="col">
A heads up!
@container
queries are very new, they have been fully supported for less than a year. Since they are so new, VSCode does not have full support for them with syntax highlighting, autocomplete, and tooltips. So you may see some weird things in your code editor.
# Writing an @container
query
In order to use the @container
and apply new styles, there are a few steps we need to complete. For the following examples, lets assume we are trying to set different styles to <a href="#" class="card">
within the html
structure above.
# Step 1: Mark the Ancestor Element as Container
To mark our ancestor element as a container, we need to apply the container-type
property. We can apply these three values:
normal
- the default value, makes the element not useable for container queriessize
- marks the element as useable for container size queries based on both inline (width by default) and block (height by default) axis.inline-size
- marks the element as useable for container size queries based on inline axis (width by default). Note: We will primarily be usinginline-size
!
.posts__list .col {
container-type: inline-size;
}
2
3
I have chosen to apply my container to .posts__list .col
because it is a column within my grid and will be controlling the width and layout of my .card
within my grid. I have chosen to apply container-type: inline-size;
because the width .col
will also reflect the same width as .card
so it is a good reference point. Also, within my layout the width
or inline
axis is the only axis I am controlling so is the only axis I need to worry about when changing my styles at different sizes.
# Step 2: Apply @container
Now that I have marked an ancestor as a container
, I can use @container
to change my styles:
@container (min-width: 30em) {
.card {
flex-direction: row;
}
}
2
3
4
5
This should feel pretty familiar as they are written very similarly to @media
. We write @container
then follow it with a size we want it to be applied to (min-width: 30em)
. Then, inside of curly brackets, we write the selectors and rules we want applied when the container matches the size we set.
You may notice that we didn't specify anywhere in the @container
which element to reference as the container. We didn't mention .posts__list .col
anywhere. That's because by default we do not have to! The browser sees that .card
has some styles it needs to apply if a container matches the (min-width: 30em)
. It then looks up through the ancestry to find the first element with container-type
applied and if it passes the condition set ((min-width: 30em)
), it will apply the styles.
# Container Name
As mentioned previously, when writing our @container
queries, we are not required to specify which container to use when applying our styles. However, we can do so if we choose using container-name
. Remembering the html structure above, consider the following css:
.posts {
container-name: posts;
container-type: inline-size;
}
.posts__list .col {
container-type: inline-size;
}
.card {
display: flex;
flex-direction: column;
}
@container (min-width: 30em) {
.card {
flex-direction: row;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Based on these styles, .card
will apply flex-direction: row;
when the .col
has a width of 30em
since .col
is the closest ancestor with a container-type
applied. If we wanted to apply the flex-direction: row;
based on the size of .posts
we could use the following instead:
@container cards (min-width: 30em) {
.card {
flex-direction: row;
}
}
2
3
4
5
By referencing the container-name
within the @container
definition, we are telling the browser exactly which element should be used as the container for our @container
query. If there is no container in our ancestry that matches the container-name
, the styles will never be applied.
# container
Shorthand
If we are setting both container-name
and container-type
on the same element, we can use the container
shorthand. You write container-name
first, then a /
, then the container-type
. The order and /
are required.
.posts {
container: posts / inline-size;
}
2
3
However, unlike other shorthands, if we are not applying both container-name
and container-type
, we cannot use the shorthand. Just setting inline-size
on container
will fail and not work. Hopefully that is updated soon!
# Container Query Length Units
From MDN (opens new window): When applying styles to a container using container queries, you can use container query length units. These units specify a length relative to the dimensions of a query container. Components that use units of length relative to their container are more flexible to use in different containers without having to recalculate concrete length values.
The container query length units are:
cqw
: 1% of a query container's widthcqh
: 1% of a query container's heightcqi
: 1% of a query container's inline sizecqb
: 1% of a query container's block sizecqmin
: The smaller value of either cqi or cqbcqmax
: The larger value of either cqi or cqb
One of the best practical uses of this is responsive font-size
based on the container:
.card__title {
font-size: clamp(1.802rem, 7.5cqi, 4.209rem);
}
2
3
Above we use a cqi
value that will set the font-size
based on the inline
size of our container. Meaning, in a large container, the font-size
will be larger and in a smaller container the font-size
will be smaller. This better uses the available space automatically. We then use clamp
to set a minimum size and a maximum size (here based on our type scales) to avoid text that is too small or too large.
# Helpful Videos
If you haven't already watched these videos, please do so. They cover the core features of @container
and related container query rules and features.
# To Do Before Week 10
Self-Directed To Do
Watch the following videos:
- intro to HTML forms
- Complete Project 1 - Two Page Website by Sunday