{"slug": "container-queries-unleashed", "title": "Container Queries Unleashed", "summary": "Container queries allow developers to style elements based on the size of their parent container rather than the viewport, enabling more flexible and responsive UI designs. The article highlights a common pattern where a metadata column changes its layout based on available space, which is difficult to manage with traditional media queries because it requires arbitrary, fragile breakpoints. Using `@container` rules provides a cleaner, more maintainable solution by directly responding to the container's width.", "body_md": "The most exciting thing about container queries, in my opinion, is that they expand what’s possible in terms of user interface design. They give us new options when it comes to responsive design, creating UIs that would be impractical or impossible using traditional media queries.\nIn this post, I’ll share the most useful pattern I’ve discovered, so that you can start taking full advantage of container queries in your own work.\nLink to this headingThe killer pattern\nThere’s one pattern in particular that I find myself using over and over again. Let’s look at an example, from this blog:\nThis layout is used to display newsletter issues.\nOn desktop, it’s a two-column layout. The email metadata on the left, the content on the right. On mobile/tablet, it collapses to a single column:\nThis is a pretty common design pattern, and it’s easily solved using media queries, but it leads to a curious side-effect: the width of each column actually increases when the viewport shrinks below the mobile threshold.\nKeep your eye on the width of the left-hand column as you shrink the (virtual) window, using the slider:\nWhen we reach the mobile threshold, our two-column layout becomes a one-column layout, which means the metadata column actually gets bigger, expanding to fill the entire width of its container.\nNow, here’s where it gets tricky. I have two different layouts for the metadata column, depending on the available space:\nSome thoughts about passion…\n- From\n- Josh W. Comeau\n- Reply-To\n- support@joshwcomeau.com\n- Sent\n- May 21, 2026\nWhen there’s enough room, I want to show the key/value pairs in a single row. Otherwise, the values should move to a new line.\nBut we want to do this based on the container’s size, not the viewport’s size! There isn’t a clear linear relationship between the two.\nHere’s the ideal behaviour. Notice how the metadata layout changes back-and-forth as the window changes size:\nWe’re using media queries to control the “top-level” layout, flipping from two columns to one column, but we can’t really use media queries to describe how the stuff within those columns should respond dynamically.\nOr, well, technically we can, but it’s messy and fragile. We could do something like this:\n.metadata-column {\n/* Condensed styles here */\n@media (min-width: 35rem) and (max-width: 42rem),\n(min-width: 60rem) {\n/* Sparse styles here */\n}\n}\nThis approach combines multiple media conditions using a comma, which acts like an OR operator. We apply the “Sparse” styles if our viewport is between 35rem to 42rem, or at least 60rem.\nBut where did these numbers come from? 35rem, 42rem, and 60rem aren’t breakpoints in our design system, they’re magic numbers. They’re the arbitrary values that happen to work given the current layout. When I’ve gone with this approach in the past, I’ve literally measured the width of the viewport at the points where I wanted it to flip.\nThis is extremely fragile. It’ll work as long as none of the styles change, but even minor tweaks like adjusting the padding on one of the columns can cause problems.\nIt’s easy to imagine another developer coming along in a few months and tweaking, say, the gap\nbetween the columns. All of a sudden, our calculated values are wrong, and the content starts to overflow near those arbitrary breakpoints. The developer probably won’t even notice, since the issue only happens at a narrow range of viewport widths, but some of our users will definitely notice!\nCheck out how much nicer the solution is with container queries:\n<style>\n.metadata-column {\ncontainer-type: inline-size;\n}\n.metadata {\n/* Condensed styles here */\n@container (min-width: 19rem) {\n/* Sparse styles here */\n}\n}\n</style>\n<div class=\"metadata-column\">\n<div class=\"metadata\">\n<!-- Stuff here -->\n</div>\n</div>\nAs we cover in “A Friendly Introduction to Container Queries”, the @container\nat-rule works just like @media\n, except it uses the size of a defined container element. We specify which element should act as the container with the new container-type\nproperty.\nInstead of 3 arbitrary numbers, we have 1 intentional number; 19rem, in this example, is the actual size that we’ve chosen for the flip, because the “sparse” layout would feel too cramped below that threshold.\nLink to this headingNamed containers\nContainers are defined using the container-type\nCSS property. This is how we create the boxes that our container queries will measure.\nOne of the lesser-known features of this API is that we can choose which container to use, if multiple ancestors establish themselves as containers.\nBy default, the nearest ancestor will be used. Try to resize the “RESULT” pane below by dragging the middle divider (or focusing and using left/right arrow keys):\nCode Playground\nResult\nThe setup here is that our .child\nelement has two container ancestors, its parent <section>\nand grandparent <main>\n. By default, the nearest ancestor will be used, and indeed, we can see that the element’s parent <section>\nis currently being used.\nWe can manually select a different container, though! Check this out:\nCode Playground\nResult\nWhen we define our container query with @container\n, we can optionally specify a container-name\n, which allows us to override the default behaviour and specify a different container!\nWe can simplify our code a bit by using the container\nshorthand property:\nmain {\ncontainer: outer / inline-size;\n/* Equivalent to: */\ncontainer-name: outer;\ncontainer-type: inline-size;\n}\nThe slash character (/\n) is a modern convention in CSS as a way to separate groups of values. It has nothing to do with division.\nLink to this headingThe dawn of a new era\nSo, I’ve been using container queries in my own work for a few months now, and it still feels to me like we’re just scratching the surface of what’s possible. ✨\nIn this blog post, we explored the killer use case I’ve discovered so far: creating sub-layouts within our media queries that expand as the viewport shrinks. I’ve used this trick all over this blog, from the Gradient Generator to my About page:\nI’ve also seen other developers discover the same pattern; Ahmad Shadeed uses it for adjusting the caption on “feature images”, and has a wonderful blog post(opens in new tab) on the subject:\nOnce you start using this pattern, you’ll see opportunities for it everywhere. 😄\nAnd this is just the tip of the iceberg. The ability to select which container is used could unlock some really interesting possibilities, allowing us to create multi-layered UIs, layouts within layouts.\nWhether anyone will be clever enough to use this stuff to its full potential remains to be seen, but it makes me excited for the future of web UIs!\nI’m going to continue experimenting with container queries, and I’d encourage you to as well. Browser engineers have given us some incredible new tech, and now it’s up to us to show them that their time was well spent. 😄\nLast updated on\nJanuary 27th, 2025", "url": "https://wpnews.pro/news/container-queries-unleashed", "canonical_source": "https://www.joshwcomeau.com/css/container-queries-unleashed/", "published_at": "2025-01-27 13:15:00+00:00", "updated_at": "2026-05-22 14:56:02.100714+00:00", "lang": "en", "topics": ["developer-tools", "products"], "entities": ["Josh W. Comeau"], "alternates": {"html": "https://wpnews.pro/news/container-queries-unleashed", "markdown": "https://wpnews.pro/news/container-queries-unleashed.md", "text": "https://wpnews.pro/news/container-queries-unleashed.txt", "jsonld": "https://wpnews.pro/news/container-queries-unleashed.jsonld"}}