Frontend Masters Boost RSS Feed https://frontendmasters.com/blog Helping Your Journey to Senior Developer Tue, 13 May 2025 16:26:47 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.3 225069128 Container Query for “is there enough space outside this element?” https://frontendmasters.com/blog/container-query-for-is-there-enough-space-outside-this-element/ https://frontendmasters.com/blog/container-query-for-is-there-enough-space-outside-this-element/#comments Tue, 13 May 2025 16:26:46 +0000 https://frontendmasters.com/blog/?p=5796 Say you had a UI component that had pagination arrows for whatever reason. If there was enough space on the outside of that component, you wanted to put those arrows outside, like this this:

But if there isn’t enough room for them without shrinking the main content area, then place them inside, like this:

You could do that with plenty of magic numbers, especially in how big the main content area is. But wouldn’t it be cool if you didn’t have to know? Like the main content area could be whatever, fluid/responsive/flexible, and you could still test if there is “room” outside for the arrows or not.

I was playing with this trick because I remember Adam Argyle talking about it one time, but couldn’t find where he used it. So I wrote this article up to re-learn and document it. Then of course I find the original article. So full credit to Adam here. Mine approach here is super similar of course. I think I prefer how his @container query uses cqi units inside of it in case the parent isn’t the viewport. Clever.

The trick is in combining viewport units within a container query. You could probably do it by using container units within a media query too, but we’ll go with the former because I tried it and it worked.

We’re going to need a “wrapper” element because that’s just how @container queries tend to be most useful. You can’t query the same element that is the container, so easier if the container is a wrapper.

<div class="box">
  <div class="box-inner">
    <div class="arrow arrow-left">
       <svg ...></svg>
    </div>
    <div class="arrow arrow-right">
       <svg ...></svg>
  </div>
</div>

The box will be the container:

.box {
  container: box / inline-size;
  inline-size: min(500px, 100vw);
}

I love using that second declaration, which says: “Make the element 500px wide, but if the entire browser window is smaller than that, do that instead.” That element is the container.

Then we can use a @container query on the inside. If we wanted to make a style change exactly when the container is the same size as the browser window, we could do this:

.box-inner {
  background: rebeccapurple;
  ...

  @container box (inline-size >= 100vw) {
    background: red;
  }
}

That will do this!

But we’re actually dealing with the arrows here, so what we want to know is “is there enough space outside for them?” Meaning not the exact size of the element, but that:

Element <= Viewport - Arrows - Gap

Which we can express like this:

.box-inner {
  background: rebeccapurple;
  ...

  @container box (inline-size <= calc(100vw - 80px * 2 - 1rem * 2)) {
    /* move arrows here */
  }
}

I’ll use a bit of translate to move the arrows here:

And here’s a video of the success:

Again what’s kinda cool about this is that we don’t know what the size of the container is. It could be changed anytime and this will continue to work. The only hard coded numbers we used were for the size of the arrow elements and the gap, which you could abstract out to custom properties if you wanted to be more flexible.

]]>
https://frontendmasters.com/blog/container-query-for-is-there-enough-space-outside-this-element/feed/ 4 5796
Using Container Query Units Relative to an Outer Container https://frontendmasters.com/blog/using-container-query-units-relative-to-an-outer-container/ https://frontendmasters.com/blog/using-container-query-units-relative-to-an-outer-container/#respond Tue, 06 May 2025 23:53:28 +0000 https://frontendmasters.com/blog/?p=5761 Recently, Matt Wilcox posted on Mastodon:

The fact you can’t specify which container for container query units is a ballache. The moment you have nested containers you’re [screwed]; because if you want the calculated gap from the row’s container; but you’re inside a nested container… tough. Your units are wrong. And you can’t just say “no; not relative to this container; relative to the named outer container!”

First off, if you’re not familiar with container queries and container query units, you can check out one of the many resources on the topic, for example this interactive guide by Ahmad Shadeed, which I believe is the most recent out of all the detailed ones I’ve seen. As always, the date of the resources used is important for web stuff, especially since these units in particular have changed their name since they were first proposed and we got an early draft of the spec.

Now, the problem at hand: let’s say we have an .inner-container inside an .outer-container – they are both made to be containers:

[class*='container'] { container-type: size }

We want any .inner-child of the .inner-container to be able to use length values set in container query units relative to the .outer-container (more precisely, to its content-box dimensions). The problem is, if we do something like this (a 20cqw light blue strip at the start of the gradient going towards 3 o’clock):

.inner-child {
  background: linear-gradient(90deg, #0a9396 20cqw, #0000)
}

… then the 20cqw value is 20% (a fifth) of the content-box width of the .inner-container. This can be seen below, where we have purple guidelines 20% of the width apart.

Screenshot illustrating how a background sized to cqw on the child of the inner container is a fifth of the inner container's width.
what 20cqw represents

But what we want is for that 20cqw value to be 20% of the content-box width of the .outer-container.

Strictly for the queries themselves, we could do something like this:

.outer-container { container: outer/ size }
.inner-container { container: inner/ size }

@container outer (min-width: 500px) {
  .inner-child { background: darkorange }
}

This allows us to set certain styles on the .inner-child elements based on where the width of the .outer-container (which isn’t the nearest container for .inner-child) is situated relative to the 500px threshold.

But we cannot do something like this to specify which container should be the one that the query units used on .inner-child are relative to:

.inner-child {
  /* can't do this */
  background: linear-gradient(90deg, #0a9396 outer 20cqw, #0000)
}

Nor can we do this:

.inner-child {
  /* can't do this either */
  --s: outer 20cqw;
  background: linear-gradient(90deg, #0a9396 var(--s), #0000)
}

However, we are getting closer!

What if we move the --s variable uspstream? After all, a 20cqw length value set on the .inner-container is 20% of the content-box width of its nearest container, which is the .outer-container. This would mean our code becomes:

[class*='container'] { container-type: size }

.inner-container {
  --s: 20cqw;
  background: 
    repeating-linear-gradient(45deg, #bb3e03 0 5px, #0000 0 1em) 
      0/ var(--s) no-repeat
}

.inner-child {
  background: 
    linear-gradient(90deg, #0a9396cc var(--s), #0000)
}

We also give the .inner-container a similar background restricted to 20cqw from the left along the x axis and make the .inner-child semi-transparent, just to check if the --s values overlap (which is what we want, --s being 20% or a fifth of the .outer-container width). However, this fails, as it can be seen below:

Screenshot. Both the inner container and its child have a background sized to 20cqw. However, the container query units are relative to the outer container only for the inner container, the container query units used on its child being still relative to the inner container (one fifth of its content-box width).
screenshot of result

For the .inner-container the 20cqw of the --s is taken to be 20% of the content-box width of its nearest container, .outer-container (dashed dark blue boundary). However, for the .inner-child, the 20cqw of the --s aren’t taken to mean the same value. Instead, they are taken to mean 20% of the .content-box width of the .inner-container (dotted dark red boundary).

Boo!

But what happens if we also register --s?

@property --s {
  syntax: '<length>';
  initial-value: 0px;
  inherits: true
}

Bingo, this works!

Screenshot. Both the inner container and its child have a background sized to 20cqw, the container query units being relative to the outer container.
desired result

I hope you’ve enjoyed this little trick.

Where would you use this?

]]>
https://frontendmasters.com/blog/using-container-query-units-relative-to-an-outer-container/feed/ 0 5761
Containers & Context https://frontendmasters.com/blog/containers-context/ https://frontendmasters.com/blog/containers-context/#comments Fri, 03 Jan 2025 19:16:32 +0000 https://frontendmasters.com/blog/?p=4904 I ran into what I thought was a z-index bug in Safari (or, Safari had it right and Chrome and Firefox had it wrong). I made a reduced test case here.

But it’s not a bug.

Stephanie Eckles let me know about a change to the specs:

RESOLVED: container-type does not force layout containment, but does force an independent formatting context

This apparently means declaring a container doesn’t force a new formatting context anymore and thus my negative z-index would “work” as I wanted it to.

Chrome and Firefox have made the change and it out in the stable version of those browsers. Safari’s update will roll out… at some point.

That’s an interesting situation isn’t it?! It looks and feels like a bug, but really it’s just a situation of a spec change and varied levels of browser support for that change. It’s not a matter of support-or-no-support of a feature, it’s a side effect. As far as I know, not practically testable. Just something that has to be lived with until all browsers implement it the same.

It’s a decently beefy change (affecting important stuff like positioning), and almost certainly for the better (because you can still force a formatting context if you want, it’s just nice to have the option). Since I became aware of this, I helped someone else having the same problem. In both cases, we totally aborted what we were trying to do as there didn’t seem to be any workaround that felt great. Probably a metaphor in there somewhere.

Despite improved tools over the years (i.e. @supports and CSS.supports()) sometimes figuring out browser support is still just hard. Guaranteed I would have been tripped up by Stoyan Stefanov’s issue with @supports and @font-face troubles as well. Good thing we blog, eh?

]]>
https://frontendmasters.com/blog/containers-context/feed/ 1 4904
How to use container queries now https://frontendmasters.com/blog/how-to-use-container-queries-now/ https://frontendmasters.com/blog/how-to-use-container-queries-now/#comments Tue, 09 Jul 2024 12:59:04 +0000 https://frontendmasters.com/blog/?p=2981 Philip Walton for Google responded to our question We’ve Got Container Queries Now, But Are We Actually Using Them? There are a variety of reasons why usage of them seems to be low, but certainly developers worried about browser support is still a factor. The biggest quoted concern is Safari 15, which is entirely reasonable.

Philip lays out a technique where you build a <responsive-container> Web Component which has a ResizeObserver that updates classes on itself you can use for fallback styles in browsers that don’t support @container.

It’s clever and efficient, but there is stuff I worry about:

  1. You can’t just update @media queries to @container queries with the same numbers, they measure very different things and will now break at different places.
  2. Every component is going to have different breakpoints, and now you need to keep those breakpoints synced in both HTML and CSS.
  3. Dealing with that style duplication is tricky. I would think a lot of setups don’t have a processing setup that has mixin abilities.

Still, if this helps you build a better system you can get to production, godspeed.

]]>
https://frontendmasters.com/blog/how-to-use-container-queries-now/feed/ 2 2981
We’ve Got Container Queries Now, But Are We Actually Using Them? https://frontendmasters.com/blog/weve-got-container-queries-now-but-are-we-actually-using-them/ https://frontendmasters.com/blog/weve-got-container-queries-now-but-are-we-actually-using-them/#comments Tue, 21 May 2024 17:34:09 +0000 https://frontendmasters.com/blog/?p=2174 When container queries didn’t yet exist and CSS developers were clamoring for them, developers went so far as to claim:

If we had container queries, most of what we write as media queries today would actually be container queries.

Like, on any given project, there would be more @container in the CSS than @media. I joined that refrain. I thought for sure it would be true, if not, more like 75%, especially considering how so many sites these days are created by composing sites through component libraries, and since components don’t know where they will be used, the CSS that style those components would use all container queries.

So, did this turn out to be true?

Anecdotally: no, not really.

Measuring usage backs that up tenfold, but that’s not fair since container queries are so relatively new, no matter how developers feel about them or use them on new projects, container queries will lag behind media queries for a very long time. Certainly the biggest two reasons for any lag in usage are:

  1. It’s new. It takes time for education about features to make it out to developers. Even when you know, old habits die hard.
  2. Browser support concern. The main one seems to be Safari 15, released as recently as 2022.

But even on new or actively developed projects where the developers know about them and the browser support choices enable usage (speaking from personal experience here, and it is polyfillable for the record), it still feels like container queries aren’t reached for all that much.

Why?!

I have a few guesses:

  1. Flexible layout methods that don’t need width/inline-size based queries. The fact that with CSS grid we can use keywords like auto-fit and auto-fill to have an arbitrary number of columns steals some of the need to specify columns at breakpoints. Also sometimes you can just… let stuff wrap.
  2. Fluid type. There are a number of ways to pull off fluid type nowdays, and that site-wide typography scaling really helps scale sites without needing breakpoints.
  3. Components that tend to really benefit from styling updates at certain sizes are full-width anyway. Think of site header and footer elements that tend to be full width. For them, media and container queries are interchangeable.

It’s the within-container layout shifts that seem like the most useful and common use case to me. My most common go-to example is essentially this:

.card {
  container: card / inline-size;
}
.card .grid {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 1rem;
  @container (inline-size < 300px) {
    grid-template-columns: 1fr;
  }
}

I’ve heard some interesting thoughts from others as well:

  • 🔗 Each container becomes a new stacking context which can cause z-index side effects that you might not want.
  • 🔗 It sometimes requires an additional wrapping element since you can’t style what you query.
  • 🔗 CSS developers are only part of a whole. If the larger team doesn’t design around the idea they may not apply.

Examples

It’s not that people aren’t using them at all. I’m using them more and more, myself. I asked folks recently if they have any examples, and got a few. Actually, the lack of responses is sort of what sparked this post.

I figured I’d post some videos of recent usage on my own project here, not all of which is live yet.

Truncate “Line” to “Ln” and “Column” to “Col” when space constrained.
Move some UI bits outside of their container to free up room for text in tight space constraints
The most classic use case of all: the Card component.
This is the combination of container-unit fluidity of the title text, and a container query breakpoint for the smaller text.
This is like a card component too, breaking into a single column when two columns are too tight.
]]>
https://frontendmasters.com/blog/weve-got-container-queries-now-but-are-we-actually-using-them/feed/ 10 2174
Container Queries and Units https://frontendmasters.com/blog/container-queries-and-units/ https://frontendmasters.com/blog/container-queries-and-units/#respond Thu, 21 Dec 2023 15:41:02 +0000 https://frontendmasters.com/blog/?p=282 Container queries are similar to media queries but allow you set styles based on a particular element’s current size, typically the width. This is super handy because you can write CSS in a way that gives flexibility to the layout!

With @media queries, there’s a tight coupling of the styling of a component’s content and the size of the browser window. This means that the styles within a given component depend on the layout.

With @container queries, we can instead tightly couple the styling of a component’s content with the size of the component itself, regardless of how that component fits into the larger layout. In short, you can set up components to respond to the container size without having to know the breakpoints of the overall page layout. Yay for increased isolation!

Let’s think through an example to illustrate this. Pulling from Michelle Barker’s helpful MDN article about container queries, here’s a mockup:

When there’s more width available, each article preview has the image on the left and copy on the right. When there’s less room available, it stacks the image on top of the content.

Without container queries, we’d have to specify which cards we want to have the vertical layout, which ones should have the horizontal layout, and which should have a bigger image explicitly. When you then consider all possible screen sizes and container layouts, this quickly becomes quite complicated.

Additionally, if there’s a possibility for the sidebar to be collapsed or if you sometimes need to show additional content (like ads) alongside this content, it gets even more complex! Not to mention when the layout gets changed to something else, like switching from 4 columns to 3, you have to go back and adjust everything.

Container queries can help us more easily address this sort of situation in a much more manageable way!

Container queries are separate from, but can be in used in combination with, the contain property The contain property is useful for performance and preventing re-renders and, crucially, the thing that made @container queries possible under the hood.

Block and inline sizing

Before diving further into container queries, it’s important to make sure we have a good understanding of block and inline sizing as it has a large impact on the container-type and the container unit(s) we use.

Inline size is equivalent to width for horizontal writing mode and equivalent to the height for vertical writing modes. The block size is the respective opposite.

Make sure you keep this in mind! The terms “block” and “inline” are from the concept of “logical properties” and the direction CSS has been heading for a while.

How to use container queries

To use container queries, you must first define a container-type and optionally a container-name.

The container-type can have a value of size, inline-size, or normal.

  • size establishes a query container for the inline and block dimensions as well as for style (which we cover at the end of this article). 
  • inline-size establishes a query container for the inline dimensions as well as for style. You’ll likely use this 99% of the time.
  • normal establishes a query container only for style.

One potential gotcha is that if you use container-type: size you need to add an explicit height. It will ignore the height of children elements. This is how it is specced to behave.

Most often, using container-type: inline-size probably makes the most sense.

The container-name is a value of the <custom-indent> type (essentially some name you make up).

You can also use the container shorthand to define both properties. Such as:

.my-component {
  container: my-component / inline-size;
}

When using a container query or container query unit (which we will cover more in later sections), it will reference the nearest container in its ancestry tree unless you specify a particular container by including the container-name.

Once you’ve defined a container, you can use a @container query and select any descendant elements inside of it. For example:

@container (min-width: 500px) {
  .my-component p {
    font-size: 1.5rem;
  }
}

Or, if you want to use the container name in the query:

@container my-component (min-width: 500px) {
  .my-component p {
    font-size: 1.5rem;
  }
}

Note that you cannot style the element that is being queried inside of the container query itself (like .my-component {} in this case). But you can use it as a part of a more complex selector as seen above.

But you don’t have to refer to the container element in the selector, meaning this is also valid:

@container my-component (min-width: 500px) {
  p {
    font-size: 1.5rem;
  }
}

You can also use nesting.

.my-component {
  @container (min-width: 500px) {
    p {
      font-size: 1.5rem;
    }
  }
}

orientation and aspect-ratio

Instead of using explicit container sizes for container queries, we can also make use of orientation and its more generic form, aspect-ratio.

For example, here’s a Pen where we have the image on the left for larger screens and on top for smaller screens (a non-aspect ratio version of this sort of thing is in the section below).

When using aspect-ratio, remember that it’s width divided by the height, so aspect-ratio < 1/1 would be when the width is larger than the height (this example is equivalent to orientation: landscape). You can also use min-aspect-ratio or max-aspect-ratio instead of plain aspect-ratio and a comparison symbol.

Note that orientation and aspect-ratio can only be used with a container-type of size because it uses the container’s width and height. Setting a height is not typically a great idea for any template-based design where content can change.

What are container query units?

Container query units are an addition to the container query specification that provides units based on the container’s dimensions. This is handy for sizing pieces of a component based on the component’s container size.

What’s more, you’re not restricted to using container query units inside of container queries. You can use them anywhere a container is specified! That means that in some cases you can get away with just setting a property’s value to something that uses a container query unit and just leave it at that.

A shortened name for container query units?

“Container query units” is kind of a mouthful to say. Given that they can be used outside of container queries (so long as a container is defined), I think we can refer to these as “container units” like Chris Coyier did when he wrote about them a while back. I’m going to call them that for the rest of this article.

Available container units

Here’s the list of container units we currently have access to:

  • 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

The width and height values are pretty straightforward to use. However, keep in mind that cqh will only use a container height if the container has a container-type of size. If inline-size is used, it will base its height on the nearest container with container-type: size, which might be the viewport.

Of these units, cqi will probably be the most commonly used unit for those who want to build websites for international audiences. For horizontal languages, it is equivalent to cqw. But it automatically switches to use cqh for vertical languages.

If you’re still not sure what inline means vs block here, maybe spend more time in the section above.

Use cases for container queries and container units

Let’s take a quick look at some use cases for container queries and container units!

Changing a component’s layout based on how much space is available

Perhaps the most common use case for container queries is to change the layout of a component’s contents based on the container’s size. Paired with ways of doing layouts like flex and grid, it can make creating pages that respond to different viewport sizes even easier.

Accessibility note: It’s best to keep the logical order of elements in the markup.

Taken to an extreme, you can make HTML and CSS components function kinda like an SVG like Dan Christofi did:

Adding non-vital detail when there’s more space available

In addition to changing the layout, sometimes it makes sense to hide some of the less important information or decorative elements when a component is smaller.

A great example of this is Chris Coyier’s calendar layout demo, where the vital parts of the calendar are kept for the smallest size but the rest is hidden:

(You may want to open this one full screen to have play.)

Fluid typography

Fluid typography is the concept of defining font sizes in a way where the type automatically scales based on some dimension between pre-defined bounds. In the past this has been based on the viewport width, but container query units make this concept a lot more powerful!

Check out this demo by Chris Coyier where you can drag to divvy up width between two elements, both with responsive type sizes:

Stephanie Eckles wrote a more in-depth article about using container query units for typography that I highly recommend!

When to use media queries instead

Content queries and units free us up from having to always use breakpoints that are tied to the layout. However, there are cases where you want content to update based on the layout! That’s when you should still use media queries—so content can be updated across multiple components at the same time.

Another time to use media queries is when you’re wanting to check certain device features, such as @media (not(hover)) { ... } or @media (not (color)) { ... } (which checks if the display is monochrome).

Browser support and style queries

Container queries for sizing have pretty solid browser support these days, as do container units.

There’s also discussion around creating style container queries. This would make certain things easier, like alternating between nested italic and normal text. Since the values of CSS variables can also be used in style queries, they could also be used as a more legitimate alternative to the CSS variable/custom property toggle hack. But at the moment they are only partially supported in WebKit-based browsers.

Conclusion

Container queries and container units enable us to create more isolated components. This makes it easier for components to be used across multiple pages, layouts, and systems. They’re prime for use in design systems!

If you’re interested in what other new CSS features I used when recreating my blog, check out my blog post about the process.

Bonus demo

This demo by SitePoint shows responsive layout paired with container queries to inspire you further!

]]>
https://frontendmasters.com/blog/container-queries-and-units/feed/ 0 282