DEV Community

Cover image for Learn to Implement CSS Container Queries
Pieces 🌟
Pieces 🌟

Posted on • Edited on • Originally published at code.pieces.app

Learn to Implement CSS Container Queries

Stylized image of shipping containers.

The media query specification was first recommended ten years ago, and it truly helped us as we transitioned towards the concept of responsive design. Since the modern web is primarily made up of components, media queries are somewhat inadequate in this context. Fortunately, container queries have emerged to address many of the issues that media queries are unable to address.

When creating a component, we frequently include a variety of versions and alter them according to the viewport size or CSS class. This isn't always the best option, and it may force us to write CSS that is dependent on a viewport size or a variation class.

What Are CSS Container Queries?

The first thing to know about CSS container queries is that “containers” are the elements being queried, but rules within container queries affect only the container descendants. In other words, you may define main as a container, or perhaps article, or even list items. With this, container queries will allow defining rules for how elements within them change across container sizes.

CSS Containment incorporates the container queries specification. The contain feature was first introduced in the CSS Containment proposal to support efficiency improvements. It offers a method for web designers to isolate DOM elements and communicate to browsers that they are separate from the rest of the document.

Using the container-type attribute, a component can check its nearest parent for defined containment.

That’s it – similar to how media queries for CSS are written, here it is applied to components.

Container Queries Syntax

To query a component based on its parent width, we need to use the container-type property. Consider the following example:

.wrapper {
  container-type: inline-size;
}
Enter fullscreen mode Exit fullscreen mode

Save this code

This allows us to begin querying a component. In the example below, we need to add a certain style if the container of the .card element has a width of 400px or more:

@container (min-width: 400px) {
  .card {
    display: flex;
    align-items: center;
  }
}
Enter fullscreen mode Exit fullscreen mode

Save this code

While the above method is effective, using many containers can make it a little overwhelming. For this reason, it's best to give a container a name:

.wrapper {
  container-type: inline-size;
  container-name: card;
}
Enter fullscreen mode Exit fullscreen mode

Save this code

The container name can now be added next to @container as shown below:

@container card (min-width: 400px) {
  .card {
    display: flex;
    align-items: center;
  }
}
Enter fullscreen mode Exit fullscreen mode

Save this code

Let's go back to the first example to see how container queries can help us avoid using several CSS classes:

.wrapper {
  container-type: inline-size;
  container-name: card;
}

.c-article {
  /* Default stacked style */
}

@container card (min-width: 400px) {
  /* Horizontal style. */
  .c-article {
    display: flex;
    align-items: center;
  }
}
Enter fullscreen mode Exit fullscreen mode

Save this code

When and Where to Use CSS Container Queries

For this project, we'll utilize plain HTML and CSS. This is our first HTML. You'll see that we've included a link to our own "styles.css file" as well:

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Container Queries</title>
 <!-- our own styles -->
    <link href="style.css" rel="stylesheet" />
  </head>

  <body>
  </body>

</html>
Enter fullscreen mode Exit fullscreen mode

Save this code

To get started, we'll make a very straightforward card with a picture, a title, and some text. A card-header with an image and a card-body with a title and other card elements will make up this card. The image remains on the left and the remaining text content is on the right because the card is styled with flex and flex-direction: row.

To center everything on the page, we'll surround this card in a container and use a div with the class parent set to big:

<body>
    <div class="container">
      <div class="parent large">
        <div class="card">
          <div class="card--header">
            <img
             class="card--image"
             src="house-project.jpg"
             alt="card image"
             width="500"
             height="400"
            />
            <!-- we have this img.jpeg file in our folder -->
          </div>
          <div class="card--body">
            <h1 class="card--title">The Customer's Choice</h1>
            <h3 class="card--content">
              You've got to start with the Customer experience and work back
              towards the technology, not the other way round. Quality in a
              product or service is not what the supplier puts in. it is what the
              the customer gets out and is willing to pay for. a product is not
              Quality because it is hard to make and costs a lot of money, as
              manufacturers typically believe.
            </h3>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Save this code

/* styles.css */
body {
 background-color: rgb(230, 205, 173);
}

.container {
 display: grid;
 place-items: center;
 grid-gap: 1em;
}

.card {
 background: white;
 border-radius: 2em;
 display: flex;
 flex-direction: row;
 overflow: hidden;
 padding: 2em;
}

.card--header {
 width: 100%;
}

.card--image {
 border-radius: 1em;
 object-fit: cover;
 height: 100%;
 width: 100%;
}

.card--body {
 padding: 2em;
 flex: 3;
}

.card--header {
 flex: 2;
}

.large {
 width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Save this code

Your page will look like this:

Our project as viewed in the browser.

The same card will be copied and pasted into a new div that has the class parent small. For the small class, we will additionally specify some styles:

<!-- index.html -->

<body>
    <div class="container">
        <div class="parent large">
            <div class="card">
              <!-- ...card -->
            </div>
        </div>
        <div class="parent small">
            <div class="card">
             <!-- ...card -->
            </div>
        </div>
    </div>

</body>
Enter fullscreen mode Exit fullscreen mode

Save this code

// styles.css

.small {
 width: 500px;
}
Enter fullscreen mode Exit fullscreen mode

Save this code

Keep in mind that both cards are identical, and are simply arranged in two distinct divs. This is how they appear:

Two container queries in the browser.

Now, let’s add container queries…

In the event that the container's width is less than 500 pixels, we want the text content to appear below the image on the card. In order for container queries to function, we must apply CSS to the container to establish the "containment context"; the children within this containment context respond to the container's properties via container queries. To contain these cards, we will create divs with the class parent. To accomplish this, we change the parent class's CSS:

/* styles.css */

.parent {
 contain: layout inline-size style;
}
Enter fullscreen mode Exit fullscreen mode

Save this code

Now, we can add container queries to our card:

/* styles.css */

@container(max-width: 500px) {
 .card {
 flex-direction: column;
 background-color: pink;
    }
}
Enter fullscreen mode Exit fullscreen mode

Save this code

The end! Now, if you return to your browser, you’ll see that the new styles have been applied to the card within the div with the class small.

Congratulations! 🎊

Rather than merely using the device characteristics, we were able to modify the styling based on the container size (screen size). This is the power of container queries.

Compatibility Issues with Container Queries

This is similar to how every website should work flawlessly across all OS platforms and browsers in software development, due to the fact that CSS is a crucial component in creating any modern website.

Given the widespread fragmentation of devices and browsers, CSS will inevitably need to be interoperable with a variety of browsers in order for a site to render flawlessly for users with various browser preferences. CSS is a styling element that is applied to all websites to improve their aesthetic appeal.

Browser Support

Container queries are only supported on Chrome Canary and Safari, and require that the enable-container-queries flag is enabled. You can download Chrome Canary here. Once installed, open the URL chrome://flags/#enable-container-queries and enable container queries:

Enable CSS Container queries in the browser.

There is a polyfill under development that you can use for container queries today. You can check it out here.

This table below shows an up-to-date list of browser support:

Chromium (Blink)

✅ Available in Chromium 106 and up.

Experimental support first appeared in Chromium 91.0.4459.0 with the #enable-container-queries flag enabled

Firefox (Gecko)

🚫 No support

Safari (WebKit)

✅ Available in Safari 16.0 and up.

Experimental support first appeared in Safari Technology Preview 142.

To stay up-to-date regarding browser support, you can follow these tracking issues:

Polyfill

A polyfill is a piece of code (or plugin) that provides the technology that you, the developer, expect the browser to provide natively. You can learn more about it in this article: What is a Polyfill?

Polyfill is not like cqfill, which is covered here. Characteristics of a polyfill for container queries include the following:

  • It does not require you to declare a separate custom property -–css-contain that duplicates the value of the contain property.
  • It does not require you to duplicate your @container rule into a @media rule.
  • It parses the newer container queries syntax that uses the container-type + container-name properties (shorthanded to container).

Because of this, the polyfill is a drop-in piece of code that will auto-magically do its thing.

A polyfill transpiles CSS code on the client-side and implements container query functionality using ResizeObserver and MutationObserver.

Additionally, this polyfill does not rely on requestAnimationFrame, which makes it more performant.

Notes

Do note that this polyfill comes with a few limitations:

  • Currently, only a small number of queries are supported. Only the following values are supported: min-width, max-width, min-height, and max-height.
  • No layering of CQs inside of other media queries is supported; only top-level container queries are.
  • The only way to provide container query thresholds is in pixels.

These restrictions are the outcome of a design decision:

In order to keep the polyfill simple(-ish), compact, and effective, we want to make sure that it functions properly for the majority of use-cases. This sounds entirely logical.

Conclusion

In time, we’ll be able to approach responsive designs in a much more intelligent way thanks to container queries. Nevertheless, container queries are still in their infancy. But as you can tell, they are easy to implement and can help developers with maintainability while working with CSS.

Top comments (2)

Collapse
 
naucode profile image
Al - Naucode

Great article, you got my follow, keep writing!

Collapse
 
fruntend profile image
fruntend

Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍