dev

Why Container Queries Rock


Container queries allow elements to respond to their parent container’s size rather than the viewport size, providing more flexible and reusable components across different contexts and layouts.

Recently I was tasked with updating a modal that’s on a company website. Not only specifically did I have to update the modal, but also the content that goes inside of it. The desired content is a pretty standard content combination in the web world, an image, with content, and the ability to adjust which side the image sits on. Also it needs stack when appropriate.

We already have such a component. I’ve called them split media blocks in the past, I’ve heard them called two column text image, and I’m sure there are other names out there as well. The problem with trying to use the split media block that’s already in use: it does not play nice with container widths less than the full width of the screen. More explicitly the CSS were written based on specific page widths, which is how responsive web designs have been coded for a long time.

In the past I would have had to create specific media queries if the split media block was nested inside the modal like so.

.modal {
  @media only screen and (max-width: 768px) {
    .split-media-block {
      // code heres
    }
  }
}

This would be added in addition to the CSS already applied to the split-media-block, so it is responsive, essentially doubling the CSS needed.

Enter Container Queries

Container queries allow elements to adapt based on the size of their parent container rather than the viewport size. This means components can be responsive to their immediate context, making them more reusable across different layouts.

The beauty of container queries is being able to fold all that responsive CSS into one group, instead of two. Review the code below.

.split-media-block__wrapper {
  container-type: inline-size;
  container-name: two-col-img;

  @container two-col-img (max-width: 576px) {
    .split-media-block__img--left,
    .split-media-block__img--right {
      flex-direction: column;
    }
  }
}

If we break it down, under split-media-block__wrapper we are declaring it a container named “two-col-img”, (Note: only container-type is required but I prefer to name the container for clarity). Next, @container two-col-img (max-width: 576px) { } states that when the container element label two-col-img, which is the wrapping element of split-media-block, is smaller than 576px, change the flex direction.

Why is that so good?

Modals, at larger screen sizes, don’t take up the full width of the window. They are capped, and as the window shrinks, so does the modal. We don’t know exact widths of the modal unless we use something like mutation observer, and it can be difficult to have the split media block stack at the right time, and not get squished, by media query alone.

The above code allows us to put the split media block anywhere and it will stack when it’s container, which is the outer most layer of the element, is smaller than 576px. Want to drop split-media-block into a modal, now you can. Want to stick it into a grid, that could have different column widths, now you can without needing tons of additional media queries so it looks good with col-3, col-6, col-8, etc, across mobile, tablet, desktop, and extra wide.

Even the modal I had to update as three widths on desktop: small, medium, and large. The modal widths can change, and split-media-content will adjust as needed based on the space available. On desktop, with medium selected, the image sits on the side, and with small selected, the image stacks on top of the content.

modal-medium modal-small These modals are taken at the same window width, using container queries.

FeatureMedia QueriesContainer Queries
Responds toViewport widthParent container width
ReusabilityLimited - components need different media queries in different contextsHigh - same component works in any container
Code efficiencyCan require duplicate rules for nested componentsSingle set of rules works in all contexts
Use casePage-level layoutsComponent-level responsiveness
Typical selector@media (max-width: 768px)@container (max-width: 576px)

Browser Support

  • Chrome: Since version 105 (August 2022)
  • Firefox: Since version 110 (February 2023)
  • Safari: Since version 16.0 (September 2022)
  • Edge: Since version 105 (August 2022)

Container queries are supported in all major modern browsers:

Conclusion

The flexibility container queries provide is immense. They allow for a more fluid and adaptable design, reducing the need for extensive media queries and making it easier to manage responsive layouts. There is widespread browser support for container queries, making them a viable option for modern web development. I plan on using container queries extensively in my future projects to create more dynamic and responsive designs.