search

CSS Container Queries – A Complete Guide (With Live Examples)

Picture this: you build a product card component. It looks perfect in the main content area – image on the left, details on the right, nice and spacious. Then your designer drops it into a 280px sidebar. It implodes. Text overflows, the image squishes, the whole thing looks like a car crash.

You reach for a media query. But wait – the sidebar is narrow on desktop too, not just mobile. Your @media (max-width: 768px) fires on phones, sure, but the card in the sidebar is still broken at 1440px because media queries have no idea where your component lives. They only know the viewport.

This is the exact problem container queries were built to solve. Drag the slider and see for yourself:

The Problem (and the Fix)
Container Width 830px
Without Container Queries
Product
Same Card
Always stacked. No idea how much space it has.
With Container Queries
Product
Same Card
Adapts its layout to the available space.

I started using them about a year ago and they changed how I think about component design. Instead of asking “how wide is the screen?”, your CSS asks “how wide is my parent?” – and that distinction matters more than you’d expect.

What Are Container Queries?

Container queries let you apply styles to an element based on the size of its parent container, not the browser viewport. The concept builds on CSS containment. You mark an element as a “container”, then write conditional styles that kick in when that container reaches certain dimensions.

The result is truly portable components. A card, a navigation menu, or a widget can adapt its layout based on whatever space it’s given. Screen size becomes irrelevant.

Container Queries vs. Media Queries

The difference comes down to what each one responds to.

Media QueriesContainer Queries
Responds toViewport / deviceParent container
ScopeGlobal (whole page)Local (component)
ReusabilityBreakpoints break when component movesSame component works everywhere
Best forPage layout, user preferencesComponent-level responsiveness

Media queries ask “how big is the screen?” Container queries ask “how much space does my parent give me?” A card in a 300px sidebar and the same card in a 900px main column get different styles automatically.

They complement each other. Use media queries for macro layout (page grid, navigation strategy) and container queries for micro layout (how individual components adapt internally).

How Container Queries Work

Setting up container queries takes two steps: define a container, then query it.

Step 1: Define a Container

Use the container-type property to mark an element as a query container:

.card-wrapper {
    container-type: inline-size;
}

The container-type property accepts these values:

  • inline-size – enables queries on the inline axis (width in horizontal writing modes). This is what you’ll use most of the time.
  • size – enables queries on both axes. Requires the container to have an explicit height.
  • normal – the default. Not a size container, but still works as a style query container.

You can also give the container a name with container-name:

.card-wrapper {
    container-type: inline-size;
    container-name: card;
}

Or use the shorthand container property (name first, then type after the slash):

.card-wrapper {
    container: card / inline-size;
}

Step 2: Query the Container

Use the @container at-rule to write conditional styles. These styles apply to the container’s descendants when the condition is met:

@container (min-width: 500px) {
    .card {
        flex-direction: row;
    }
}

You can also use the modern range syntax, which reads more naturally:

@container (width > 500px) {
    .card {
        flex-direction: row;
    }
}

@container (300px < width < 600px) {
    .card {
        font-size: 0.9em;
    }
}

To target a specific named container:

@container card (width > 500px) {
    .card {
        flex-direction: row;
    }
}

Without a name, @container targets the nearest ancestor with a containment context. Naming your containers avoids unexpected behavior as your component tree grows.

Live Examples

Drag the sliders below to resize each container and watch the components adapt in real time.

Responsive Card Component

This card switches between a vertical (stacked) and horizontal (side-by-side) layout depending on its container width. The breakpoint is at 420px.

Responsive Card
Container Width 460px
Featured
Container Queries
Components that adapt to their available space, not the viewport.

Adaptive Sidebar Navigation

This navigation shows only icons when narrow and expands to show labels when the container is wide enough. The same component works in a collapsed 60px sidebar or a full 240px sidebar – no viewport breakpoints needed.

Adaptive Navigation
Sidebar Width 180px

Dashboard Widget

A stats widget that shows a compact number-only layout in small containers and expands to include a mini bar chart when there’s enough room.

Dashboard Widget
Widget Width 320px
Revenue +12%
$48,250

Container Query Length Units

Container queries also introduce a set of length units relative to the container’s dimensions, similar to viewport units but scoped locally:

UnitMeaningViewport Equivalent
cqw1% of container widthvw
cqh1% of container heightvh
cqi1% of container inline sizevi
cqb1% of container block sizevb
cqminSmaller of cqi or cqbvmin
cqmaxLarger of cqi or cqbvmax

These are useful for fluid typography and spacing that scales with the container:

.card-title {
    font-size: clamp(14px, 10px + 1.5cqi, 22px);
    padding: clamp(0.5rem, 5cqi, 1.5rem);
}

If no eligible container exists in the ancestor tree, these units fall back to the corresponding small viewport units.

Gotchas and Limitations

Container queries have a few sharp edges that trip up beginners:

Containers cannot style themselves. You can only style descendants inside a @container rule. The container element itself is off-limits. Think of it as “you cannot style what you query.”

Containers must get their size externally. Setting container-type: inline-size establishes size containment. This means the container’s width is calculated ignoring its children. The container needs to get its size from the layout context – a CSS Grid cell, a Flexbox parent, or an explicit width.

You cannot use var() in query conditions. This does not work:

/* This is invalid and will be ignored */
@container (min-width: var(--breakpoint)) {
    .card { flex-direction: row; }
}

container-type: size requires explicit height. If you need to query both width and height, the container must have a defined height. In most cases, inline-size is all you need.

Avoid making <html> or <body> containers. Applying container-type to root elements can cause unexpected layout behavior. Use semantic elements like <main>, <aside>, or wrapper divs instead.

Browser Support

Container size queries have excellent browser support as of 2026:

BrowserSupported Since
Chrome106+ (Sep 2022)
Edge106+ (Sep 2022)
Firefox110+ (Feb 2023)
Safari16.0+ (Sep 2022)
Safari iOS16.0+

Container size queries have roughly 96% global browser support and are considered production-ready. No polyfill needed for modern projects.

FAQs

Common questions about CSS container queries:

Do container queries replace media queries?
No. Container queries and media queries serve different purposes. Use media queries for page-level layout decisions and user preferences like prefers-color-scheme or prefers-reduced-motion. Use container queries for component-level responsiveness where elements need to adapt to their available space.
Can I nest container queries?
Yes. You can nest @container rules. A nested query targets the nearest matching ancestor container. If you name your containers, the inner query targets the named container while the outer query targets a different one. This is useful for components inside components that each need their own responsive behavior.
Can I use container queries with Flexbox and Grid?
Yes. Container queries work with any layout method. In fact, Flexbox and Grid are ideal for providing the external sizing that containers need. A common pattern is making a Grid cell or Flex item's wrapper the container, then querying it inside the component.
What happens if no container is defined in the ancestor tree?
If no ancestor has container-type set, unnamed @container queries will not match and their styles will not apply. Container query length units like cqi will fall back to the corresponding small viewport units (svi). Always make sure a container is defined somewhere in the ancestor chain.
What are container style queries?
Style queries let you apply styles based on a container's CSS custom property values using @container style(--theme: dark). Unlike size queries, every element is implicitly a style container - no container-type needed. As of 2026, style queries for custom properties work in Chrome, Edge, and Safari, but not yet in Firefox.
Can a container style itself with container queries?
No. A @container rule can only style the container's descendants, never the container element itself. If you need to style the container based on its own size, add an inner wrapper element and make the outer element the container.

Summary

Container queries let your components respond to their available space instead of the viewport. Define a container with container-type: inline-size, query it with @container, and your component adapts wherever it’s placed – sidebar, main content, modal, dashboard grid.

Combined with CSS Grid and Flexbox for layout, container queries complete the picture for building truly reusable, responsive components.

Join the Discussion
0 Comments  ]

Leave a Comment

To add code, use the buttons below. For instance, click the PHP button to insert PHP code within the shortcode. If you notice any typos, please let us know!

Savvy WordPress Development official logo