CSS

CSS Container Queries, what are they?

Jesús Padrón
6 min read
Jesus - CSS Container queries

CSS Container queries, what are they?

Intro

Media queries have always been crucial to building web applications. They help make our apps more accessible and easier to use and ensure we reach most of our audience. Media queries have been essential in frontend development to create unique user interfaces.

But now, there’s something new: Container queries.

In this blog post, we’ll explore what Container queries are, how they differ from media queries, and why they’re so amazing.

So, let’s get started!

Refresh on Media queries

Media queries have been available in browsers for a long time, but they didn’t become popular until around 2010 when mobile devices started to take off.

Media queries let us add specific styles based on the type of device, like screens or printers. This is especially helpful for creating modern, responsive apps.

A simple use of Media queries would be changing, for example, a paragraph's font size when the screen width is less than a specific number.

p {
  font-size: 12px
}

// Media query
@media screen and (min-width: 400px) {
 p {
   font-size: 8px
 }
}

In this simple example, when the browser’s viewport width is less or equal to 400px, the font size changes to 8px.

Notice how straightforward the syntax is: we start with the keyword @media, followed by the type of device it should apply to. In this case, we use screen so it doesn’t affect users who print the page—if you don’t add anything, then it falls back to the default, which is “all” including both print and screen. Then we specify a media feature, in this case, the width.

Container queries

Container queries are similar to Media queries. Their main function is to apply styles under certain conditions. The difference is that instead of listening to the viewport of the browser, it listens to a container size. Let’s see this example:

dashboard screenshot 1

In the above layout, we have a layout with a sidebar and three cards as the content. Using Media queries we could listen to the viewport width and change the layout depending on a specific width. Like so:

@media (max-width: 768px) {
  .layout {
    flex-direction: column;
  }

  .sidebar {
    width: 100%;
    border-right: none;
    border-bottom: 1px solid #333;
  }

  .card-inner {
    flex-direction: column;
  }

  .card-left {
    border-right: none;
    border-bottom: 1px solid #333;
  }
}

dashboard screenshot 2

That’s acceptable, but it requires us to constantly monitor the layout. For example, if we added another sidebar on the right (really weird, but let’s imagine that this is a typical case), our layout would become more condensed:

dashboard screenshot 3

We would need to change our media queries and adjust their range in this situation. Wouldn’t it be better to check the card container’s width and update its styles based on that? That way, we wouldn’t need to worry about if the layout changes, and that’s precisely what container queries are made for!

First, to define the container we are going to listen to, we are going to add a new property to our styles:

// cards container
.container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  justify-content: flex-start;
  // new property to define our container
  container-type: inline-size;
}

The .container class is the one in which our cards reside. By adding the property `container-type, ' we now define this class as a container we want to listen to. We said inline-size as the value to query based on the inline dimensions of the container because we just want to listen to the element's width.

The value of container-type will depend on your use case. If you want to listen to both width and height, then size will be a better fit for you.

You can also have normal as your container-type value, which means the element won’t act as a query container at all. This is handy if you need to revert to the default behavior.

Next, to define our query, we use the new @container CSS at-rule:

@container (max-width: 400px) {
  .card-inner {
    flex-direction: column;
  }

  .card-left {
    border-right: none;
    border-bottom: 1px solid #333;
  }
}

Notice that it is really similar to how we define our Media queries. Now, if we look at the same screen, we will see the following:

dashboard screenshot 4

This is very powerful because we can now style each component with its own rules without changing the rules based on the layout changes.

The @container will affect all the defined containers in the scope; we might not want that. We can define the name of our container to specify that we only want to listen to that in specific:

.container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  justify-content: flex-start;
  container-type: inline-size;
  // New property to define the name of our container
  container-name: cards-container;
}

//We now specify which container we are listening to
@container cards-container (max-width: 400px) {
  .card-inner {
    flex-direction: column;
  }

  .card-left {
    border-right: none;
    border-bottom: 1px solid #333;
  }
}

We can also have a shorthand to define our container and its name:

.container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  justify-content: flex-start;
  // name of our container / its type
  container: cards-container / inline-size;
}

Container query length units

Container query lengths are similar to the viewport-percentage length units like vh or vw units, but instead of being relative to the viewport, they are to the dimensions of the query container. We have different units, each relative to different dimensions of the container:

  • 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

In our example, we could use them to define the font size of our cards:

.card p {
  // Pick the maximum value.
  font-size: max(16px, 1cqi);
}

Using these units alone isn’t recommended because they’re percentage-based and can have a value we don’t want. Instead, it’s better to use a dynamic range. Using the max function, we can set 2 values and always pick the highest one.

Conclusion

Container queries bring a fresh and powerful approach to web design but are not meant to replace Media queries. I think their real power shines when used together.

Media queries often require constant adjustments as your layout evolves. Container queries, however, let you style individual components based on their dimensions, making the designs more flexible and easier to manage.

Adding a new component or rearranging elements won’t force us to rewrite our media queries. Instead, each component handles its styling, leading to cleaner and more organized code.

Please note that, as of writing this blog post, they aren’t compatible with all browsers yet. Take a look at this table from caniuse.com:

can I use css container style queries

A good fallback strategy for this, when hitting an unsupported browser would be the use of the @support rule, which allows you to apply styles only if the browser supports the CSS feature. For example:

/* Fallback for browsers that don't support container queries */
@supports not (container-type: inline-size) {
  @media screen and (max-width: 1024px) {
    .card-inner {
      flex-direction: column;
    }

    .card-left {
      border-right: none;
      border-bottom: 1px solid #333;
    }
  }
}

@container cards-container (max-width: 400px) {
  .card-inner {
    flex-direction: column;
  }

  .card-left {
    border-right: none;
    border-bottom: 1px solid #333;
  }
}

Ensure your media queries are good enough to keep everything responsive and user-friendly when the condition is unmet.

Thank you for reading! Enjoy the extra flexibility that container queries bring to your web designs. Check out a live demo to see it in action. Happy styling!

About the author

Jesús Padrón

Jesús Padrón

Software Engineer

Keep reading

View all posts →

An example-based guide to CSS Cascade Layers

CSS Cascade Layers make style management simple—see how in this example-driven guide....

Dane Grant4 mins
CSS

Understanding the Difference Between `:focus` and `:focus-visible` in CSS

Understanding the Difference Between :focus and :focus visible in CSS I have learned my fair share about the importance of keyboard accessibility, so I know that visual indication of the focused element is very important. But the well known :focus pseudo class is not always the best fit for this job. That's where :focus visible comes in. Let's look at the differences between these two pseudo classes and explore the best practices for using them effectively. What is the :focus Pseudo Class? The :focus pseudo class is a CSS selector that applies styles to any element that receives focus, regardless of how that focus was triggered. This includes focus events from keyboard navigation, mouse clicks, and touch interactions. Example Usage of :focus In this example, the button will display a blue outline whenever it is focused, whether the user clicks on it with a mouse, taps it on a touchscreen, or navigates to it using the keyboard. What is the :focus visible Pseudo Class? The :focus visible pseudo class is more specialized. It only applies styles to an element when the browser determines that the focus should be visible. This typically occurs when the user navigates via the keyboard or assistive technologies rather than through mouse or touch input. Example Usage of :focus visible Here, the button will only show a blue outline when focused through keyboard navigation or another input method that usually requires visible focus indicators. Key Differences Between :focus and :focus visible :focus Behavior: Applies to any element that receives focus, regardless of the input method. Use Cases: Ensures that all interactions with the element are visually indicated, whether by mouse, keyboard, or touch. :focus visible Behavior: Applies styles only when the focus should be visible, such as using a keyboard or assistive technology. Use Cases: Ideal for scenarios where you want to provide focus indicators only to keyboard and assistive technology users while avoiding unnecessary outlines for mouse and touch users, typically required by design. Accessibility Implications :focus Pros: Guarantees that all users can see when an element is focused, which is critical for accessibility. Cons: Can lead to a suboptimal experience for mouse users, as focus styles may appear unnecessarily during mouse interactions. :focus visible Pros: Enhances user experience by showing focus indicators only when necessary, thus keeping the interface clean for mouse and touch users. Tailors the experience for keyboard and assistive technology users, providing them with clear visual cues. Cons: Additional considerations may be required to ensure that focus indicators are not accidentally omitted, especially in older browsers that do not support :focus visible. There may be cases where you want to show focus indicators for all users, regardless of input method. Best Practices for Using :focus and :focus visible To achieve the best accessibility and user experience, combining both :focus and :focus visible in your CSS is often a good idea. Combining :focus and :focus visible Here is a Stackblitz example of what such styling could look like for you to try out and play with. Additional Tips Test with Keyboard and Assistive Technology: Ensure that your web application is navigable using a keyboard (Tab, Shift + Tab, etc.) and that focus indicators are visible for those who rely on them. It's never a bad idea to include accessibility testing in your e2e testing suite. Provide Clear Focus Indicators: Make sure that focus indicators are prominent and easy to see. A subtle or hard to spot focus indicator can severely impact accessibility for users who rely on keyboard navigation. Conclusion The :focus visible pseudo class offers a more refined way to manage focus indicators, improving accessibility and user experience, particularly for keyboard and assistive technology users. By understanding the differences between :focus and :focus visible, and applying best practices in your CSS, you can create more accessible and user friendly web applications. Remember, accessibility should never be an afterthought. By thoughtfully applying focus styles, you ensure that all users, regardless of how they interact with your site, can easily navigate and interact....

Jan Kaiser3 mins
AccessibilityCSSPlaywright

How to Truncate Strings Easily with CSS

Learn how to truncate text in CSS, focusing on single-line and multi-line truncation using properties like overflow, text-overflow, and -webkit-line-clamp. It highlights CSS’s simplicity and responsiveness compared to JavaScript-based truncation....

Mark Shenouda4 mins
CSS

:where functional pseudo-selectors :is valuable in CSS

Simplify your CSS and add dynamic styling without JS or pesky !important tags using CSS functional pseudo-selectors...

Dan Spratling4 mins
CSS