Web Design

Container queries changed everything — The day I stopped writing media queries

William Mayer William Mayer Design Lead

Reviewed by Jordan Heppleston, Founder & Director

Talk to Our Web Team
Container queries changed everything — The day I stopped writing media queries

I remember the exact moment it clicked. It was late. I had a lukewarm tea on the desk and a homepage hero that refused to behave at tablet breakpoints. Every tweak to a media query fixed one thing and nudged something else out of place. Then I did one tiny thing. I declared a container on the hero and wrote a single query against its width. The layout slid into place as if it had been waiting for me to ask the right question. Since then I have barely reached for viewport media queries in component work. Not because they are bad, but because there is finally a better fit for most of the problems we actually have.

Container queries let components respond to the space they live in rather than the size of the browser window. They are not a trick or a polyfill or a preprocessor dream. They are in the platform and widely available across modern browsers. If you have been holding off, you can ship this today with confidence.

The other good news is scope. Support for size based container queries is now over nine in ten users worldwide, and the ergonomics are pleasant once you get the hang of the couple of new properties. You give an element container status, usually the parent that wraps the component, then write a query with @container. That is it. No magic. Just the right level of control.

The tiny change that unlocks it

We start by telling the browser which element is a query container. The easiest way is the shorthand container, or use container-type plus an optional container-name if you want to target it explicitly.

HTML
<section class="hero">
<div class="hero__content">
<h1>Grow without the bloat</h1>
<p>Simple pricing and no surprises.</p>
<a class="cta">Get started</a>
</div>
<img class="hero__image" src="hero.jpg" alt="">
</section>

CSS
/* Make the wrapper a size container so its children can query it */
.hero { 
container: hero / inline-size; /* name + type in one line */
/* or: container-type: inline-size; container-name: hero; */
}

/* Base layout stacks content and image */
.hero__content { max-width: 60ch; margin-inline: auto; }
.hero { display: grid; gap: 1rem; }

/* When the hero has enough room, switch to a split layout */
@container hero (min-width: 52rem) {
.hero { grid-template-columns: 1fr 1fr; align-items: center; }
.hero__image { order: 2; }
}

No viewport breakpoints. No global assumptions. The hero behaves correctly wherever it is placed, including inside a narrow column on a content page. The trick is simply remembering to declare the container. You cannot query space you have not marked as queryable.

Rebuilding a hero without media queries

Let us make it a little more real. The brief is a familiar one. Big statement on the left when there is room, single column when there is not, and a quiet shift in typography so the headline never feels cramped.

.hero { 
container: hero / inline-size; 
display: grid; 
gap: 1.2rem; 
padding: 2rem; 
}

.hero__content h1 { 
font-size: clamp(1.75rem, 4vw, 3rem); 
line-height: 1.1; 
}

/* Split layout kicks in based on the hero space, not the viewport */
@container hero (min-width: 48rem) {
.hero { grid-template-columns: 1fr 1fr; gap: 2rem; }
}

/* Give the headline more presence only when the hero is wide enough */
@container hero (min-width: 62rem) {
.hero__content h1 { font-size: clamp(2.25rem, 3vw, 4rem); }
}

You can drop this hero into a sidebar layout, a full width landing page, or a third of a dashboard card and it adapts with zero extra work. That sense of calm you feel while reading the code is why teams fall hard for this approach.

If you ever forget the syntax or want to check what counts as a valid container type, the MDN pages on container and container-type are excellent quick references, and they include the baseline note that this has been broadly available since early 2023.

Cards and grids that respect their slot

Cards are where container queries shine. You define a card list as the container, then let each card adjust its inner layout when it gets enough room.

HTML
<ul class="product-list">
<li class="card">
<img class="card__img" alt="">
<h3 class="card__title">Starter</h3>
<p class="card__copy">All the basics for small teams</p>
<a class="card__cta">Choose plan</a>
</li>
<!-- more cards -->
</ul>

CSS
.product-list { 
display: grid; 
gap: 1rem; 
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); 
container: cards / inline-size; 
}

.card { 
border: 1px solid oklch(0.9 0 0); 
padding: 1rem; 
display: grid; 
gap: 0.75rem; 
}

/* Upgrade the card layout when the list gives it more room */
@container cards (min-width: 62rem) {
.card { grid-template-columns: 8rem 1fr; align-items: start; }
.card__img { width: 100%; aspect-ratio: 1; object-fit: cover; }
}

Notice that we are not making assumptions about the viewport at all. The grid can live in a narrow column and still look great.

Container query units for effortless scale

There is a lovely extra once you are comfortable. Container query units give you lengths tied to the container itself. That means fluid typography or spacing that scales with the component’s actual slot, not the window.

CSS

/* cqi is the inline size unit, cqb is the block size unit */
.pricing { container: pricing / inline-size; }

/* Headline grows with its container but stays sensible */
.pricing__title { font-size: clamp(1.25rem, 6cqi, 2.25rem); }

/* Padding breathes on large cards but never feels wasteful */
.plan { padding: clamp(1rem, 4cqi, 2rem); }
 

Support for container units is strong on modern engines, and the units include cqw, cqh, cqi, cqb, cqmin, and cqmax. If you prefer a friendly explainer before you dive into a table, the CSS Tricks guide is a good tour that maps units to intuitive mental models.

Common gotchas and simple fixes

I tripped over the same handful of things at the start. You might too.

First, nothing works until you establish a container. Add container-type: inline-size to the parent you want to query, or use the shorthand. Second, queries only test ancestors that are containers, so you may want a wrapper that exists purely to provide a clean boundary for a component. Third, naming helps. If you give the container a name, you can compose multiple queries with clarity when you nest components, like @container sidebar (min-width: 40rem) { … }. The MDN reference spells this out with small, copyable examples.

Fourth, do not confuse container queries with media queries. Media queries still shine for big page level changes, such as repositioning the entire sidebar at certain viewport sizes. Container queries live lower in the tree where components need to be resilient in many contexts. The MDN article on container queries is a good place to refresh that difference if you have been away from CSS for a while.

A tiny side door with modern selectors and nesting

Once you start thinking in components, a few modern CSS features become obvious companions. The :has() pseudo class lets you style a parent based on what it contains. Think of an input group that changes the wrapper border when the inner input is invalid, or a card that tweaks spacing if it contains an image. This is more than a parent selector party trick and pairs beautifully with container logic.

And if you have not tried native CSS nesting yet, it is worth a go. It keeps related rules together with less repetition and works across modern browsers with very good coverage. The MDN usage guide shows where to place the ampersand for clarity when you need it.

Debugging without drama

You can inspect and debug container queries in Chrome DevTools. There is a specific panel section that shows which containers apply and when queries match, which saves a lot of guesswork when a nested component behaves in a surprising way. Once you have seen the visual overlay mark the container edges, you will not want to debug without it. Chrome for Developers

Performance and care notes

Container queries themselves are not a performance tax. They encourage cleaner boundaries which often reduces layout thrash. In practice I have seen simpler CSS, far less duplication, and fewer fragile overrides. If you add motion on top, remember our duty of care. Respect user preferences for reduced motion, and lean on the platform for transitions rather than heavy libraries. If you are curious, the View Transition API is a gentle way to add wayfinding without turning your site into a carnival ride.

Copy and paste starters

A few snippets you can use as a base today.

Named container with a couple of breakpoints

CSS
.section {
container: section / inline-size;
display: grid;
gap: 1rem;
}

@container section (min-width: 42rem) {
.section { grid-template-columns: 1fr 1fr; }
}

@container section (min-width: 64rem) {
.section { grid-template-columns: 2fr 1fr; }
}

Component that switches layout inside a wider container

.card { 
container: card / inline-size; 
display: grid; 
gap: 0.75rem; 
}

@container card (min-width: 30rem) {
.card { grid-template-columns: 10rem 1fr; }
.card__img { aspect-ratio: 1; object-fit: cover; }
}

Fluid type tied to component space with container units

.feature { container: feature / inline-size; }
.feature__title { font-size: clamp(1.25rem, 5cqi, 2.5rem); }
.feature__copy { font-size: clamp(1rem, 2.5cqi, 1.125rem); }

Quick answers you can share with the team

Do I still need media queries
Yes for page level layout and device features. Use container queries for component behaviour so pieces do not depend on where you place them. MDN shows the conceptual split clearly.

What is the minimum I must write to make this work
Give the parent a container type, usually inline size, then write @container (min-width: …) { … }. The shorthand is convenient and the MDN reference is a good checklist.

Can I rely on support right now
For size based queries the answer is yes for the vast majority of users, and adoption continues to climb. If your audience is very legacy heavy, check a fresh support table before you commit.

Are style queries real yet
Style based container queries exist but are newer and the picture varies. Great for progressive enhancement if you have a clear use case. Keep an eye on capability tables as engines roll out improvements.

What to do next

Pick one component that has always been a nuisance. A hero, a pricing card, a feature block, anything that gets moved around a lot. Wrap it in a named container, set container-type: inline-size, and replace your first media query with @container. Watch how the component begins to feel self aware and less brittle. Then do it again tomorrow with the next most annoying component.

If you want the exact demo files from this article plus a few extras, grab the Modern CSS Cookbook and start a small internal pattern library. Add one container powered component a week and your future self will thank you.

Helpful references for your bookmarks
MDN container queries, MDN container and container type pages, DevTools guide for debugging, Can I Use for support, and a friendly explainer on container units. That set will keep you honest and fast.
MDN Web Docs+1

Chrome for Developers

Can I Use+1

Want results like these for your business?


If you have read this far, you are clearly serious about your digital presence. Let us have a conversation about what we can do for you.

Office: Floor 1, Lindpet House, Grantham NG31 6LJ

Whether it's a brand-new website, a marketing campaign, or just a quick question - we'll get back to you within one working day. No hard sell, no jargon, just straight answers.

Let's talk!

Fill out the form below and we'll get back to you within 24 hours.

We'll never share your data. See our privacy policy.

Thank you

We've received your message and will be in touch within one working day.