# 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>
1
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 queries
  • size - 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 using inline-size!
.posts__list .col {
  container-type: inline-size;
}
1
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;
  }
}
1
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;
  }
}
1
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;
  }
}
1
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;
}
1
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 width
  • cqh: 1% of a query container's height
  • cqi: 1% of a query container's inline size
  • cqb: 1% of a query container's block size
  • cqmin: The smaller value of either cqi or cqb
  • cqmax: 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);
}
1
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
Last Updated: 10/22/2023, 3:02:31 PM