Media queries ask one question: how wide is the browser window? That works for page layout, but a card does not care about the window. It cares about the space it has been given. CSS container queries let a component look at the size of its own box on the page and change its layout to fit, wherever you drop it.
This guide covers why container queries exist, the three properties you need, the @container rule, container query units such as cqi, six practical examples, style queries, browser support and the mistakes I see most in junior code. If responsive layout is still new to you, start with the CSS Responsive Design lesson.
Why CSS container queries exist
Picture a product card. In the main column it has 800px of room, so the image can sit beside the text. In a 300px sidebar the same card should stack. With media queries alone you end up writing rules like .sidebar .card and guessing breakpoints from the viewport, even though the viewport tells you nothing about the sidebar.
Container queries flip the question. You mark an element as a container, and its descendants can ask how wide that container is. The card then works in a sidebar, a modal, a grid cell or a full-width section without extra classes. Media queries still have a job: the overall page layout, which I cover in how to choose responsive breakpoints.
| Media queries | Container queries | |
|---|---|---|
| What they measure | The viewport (or device features) | The size of an ancestor container |
| Best for | Page layout: header, columns, sidebar on or off | Reusable components: cards, navs, widgets |
| Setup needed | None | Declare a container with container-type |
| Rule | @media | @container |
Setting up a container: container-type, container-name and container
Nothing is a size container by default. You opt in with container-type. MDN lists these values for size queries:
inline-size: lets descendants query the inline size (the width in English and Tamil text). It applies style and inline-size containment. This is the value you will use almost every time.size: lets descendants query both width and height. It applies size containment in both directions, so the element can no longer get its height from its content.normal: the default. The element is not a size container, but it can still be used for style queries and name-only queries.
MDN also lists newer values, scroll-state and anchored, for other kinds of container queries. They are outside the scope of this beginner guide.
container-name gives the container a name so a query can target it directly instead of the nearest container. The container shorthand sets both at once, name first, then a slash, then the type:
/* Longhand */
.sidebar {
container-name: sidebar;
container-type: inline-size;
}
/* Same thing with the shorthand */
.sidebar {
container: sidebar / inline-size;
}The @container rule and container query units
An @container rule looks like a media query. You can add an optional name, then a size condition. The features you can test are width, height, inline-size, block-size, aspect-ratio and orientation. The range syntax (width >= 600px) works, and so does the older min-width form.
/* Nearest ancestor container */
@container (width >= 600px) {
.card { grid-template-columns: 200px 1fr; }
}
/* Only the container named "sidebar" */
@container sidebar (width < 280px) {
.card__meta { display: none; }
}Without a name, the query checks the nearest ancestor that is a suitable container. With a name, it checks the nearest ancestor that has that name. Size queries measure the container’s content box, so padding is not included.
Container query units
Container queries also bring their own length units, similar to vw and vh but relative to the container. If you need a refresher on units in general, see px vs rem vs em vs vw.
| Unit | Equals |
|---|---|
cqw | 1% of the container’s width |
cqh | 1% of the container’s height |
cqi | 1% of the container’s inline size |
cqb | 1% of the container’s block size |
cqmin | The smaller of cqi and cqb |
cqmax | The larger of cqi and cqb |
If there is no eligible container, MDN says these units fall back to the small viewport units for that axis (svw, svh and so on). I prefer cqi over cqw because it follows the writing direction.
Six practical CSS container queries examples
1. A card that changes layout in a sidebar vs the main column
Wrap the card in a container so the card itself can be styled by the query. The card stacks by default and switches to two columns only when its wrapper is wide enough.
.card-wrap {
container-type: inline-size;
}
.card {
display: grid;
gap: 1rem;
}
@container (width >= 480px) {
.card {
grid-template-columns: 180px 1fr;
align-items: start;
}
}Put the same markup in the main column and in the sidebar. Without any extra class, the main column version sits side by side and the sidebar version stacks.
2. Named containers for page regions
When containers are nested, naming them avoids surprises. Here the sidebar and main area are named, and a rule only targets cards inside a narrow sidebar.
.sidebar { container: sidebar / inline-size; }
.main { container: main / inline-size; }
@container sidebar (width < 280px) {
.card__meta { display: none; }
}3. A responsive nav inside a component
A header block may be full width on one page and squeezed beside a logo on another. Let the nav react to its own header rather than the screen.
.site-header {
container: header / inline-size;
}
.nav__links { display: none; }
.nav__toggle { display: block; }
@container header (width >= 720px) {
.nav__links { display: flex; gap: 1.5rem; }
.nav__toggle { display: none; }
}Tip: Hiding links with display: none also hides them from screen readers. Make sure the toggle button opens a menu that contains the same links, with a proper aria-expanded state.
4. Fluid typography with cqi
Combine cqi with clamp() so a heading scales with its card but never gets too small or too large. Keep a rem part in the middle value so the text still responds to the user’s browser font size. Our CSS clamp generator can help you pick the numbers.
.card-wrap {
container-type: inline-size;
}
.card__title {
font-size: clamp(1.125rem, 0.75rem + 3cqi, 1.75rem);
}5. A product grid that counts its own columns
A listing block can choose one, two or three columns based on its own width. This pairs well with CSS Grid; if you are unsure which layout tool to use, read Flexbox vs Grid.
.products {
container-type: inline-size;
}
.products__list {
display: grid;
gap: 1rem;
grid-template-columns: 1fr;
}
@container (width >= 520px) {
.products__list { grid-template-columns: repeat(2, 1fr); }
}
@container (width >= 820px) {
.products__list { grid-template-columns: repeat(3, 1fr); }
}6. A style query for a card variant
Style queries ask about a container’s computed style instead of its size. Every element can be a style container, so you do not need container-type. At the time of writing, browsers only support querying custom properties, not normal properties like color.
.card-wrap--featured {
--variant: featured;
}
@container style(--variant: featured) {
.card {
border: 2px solid var(--accent, #2563eb);
}
}Style queries and browser support
Size container queries are well supported. MDN marks container-type as Baseline Widely available, working across browsers since February 2023. According to caniuse, full support arrived in Chrome and Edge 106, Safari 16 and Firefox 110.
Style queries are much newer. Chrome and Edge shipped them earlier, but Firefox only added style() queries on @container in Firefox 151. The web.dev Baseline digest for May 2026 lists container style queries as Baseline Newly available, not Widely available. Users on older browsers will not get them, so treat style queries as an enhancement and check the MDN @container page before relying on them. Support changes over time, so check the current tables before you ship.
Common mistakes with CSS container queries
- Expecting a container to query itself. A query is answered by an ancestor container. If you put
container-typeon.cardand then write@container (width > 500px) { .card { … } }, the.cardrule looks at a container above it, not at itself. Add a wrapper and style the children. - Forgetting to declare a container. A size query with no eligible ancestor container never matches. Nothing breaks loudly; the styles simply never apply.
- Using
sizewhen you meantinline-size. Size containment means the element’s height no longer comes from its content. Unless you give it a height, it can collapse to zero and the content spills out. - Ignoring inline-size containment. With
inline-size, the container’s width cannot depend on its children. A container that relies on its content for width, such as aninline-block, a float or a flex item without a set width, can shrink to almost nothing. Give it a width from its parent instead. - Replacing every media query. Page-level layout, print styles and user preferences like
prefers-reduced-motionstill belong in@media. - Using container units outside a container. They quietly fall back to small viewport units, which may not be what you expect.
Tip: When a query does not apply, inspect the element in your browser’s DevTools and check which ancestor has container-type set. Chrome DevTools marks containers with a container badge in the Elements panel.
Start small: pick one card in your project, wrap it, and convert its media queries to CSS container queries. Test it in the code playground, resize the container, and you will see the idea click.
Frequently asked questions
Do container queries replace media queries?
No. Use media queries for the overall page layout and user preferences, and container queries for reusable components that need to fit whatever space they are placed in.
What is the difference between cqw and cqi?
cqw is always 1% of the container’s width. cqi is 1% of its inline size, which is the width in horizontal writing modes like English or Tamil but the height in vertical writing modes.
Can I use container queries in production?
Size container queries have been available across major browsers since February 2023 and MDN lists them as Baseline Widely available. Style queries became Baseline Newly available only in May 2026, so use them as an enhancement.
Why is my container query not working?
The most common causes are: no ancestor has container-type set, you are trying to style the container itself, or a named query uses a name that does not match the container-name.


