CSS Container Queries

Make components respond to the space they're placed in, not the screen: container-type, @container rules, named containers and container query units.

Lesson 40 of 49Advanced15 min read

Media queries ask one question: how wide is the screen? For whole-page layouts that's fine. But modern sites are built from reusable components, such as product cards, profile panels and widgets, and the same card might appear in a wide main column, a narrow sidebar and a three-column grid on the same page. The screen width tells you nothing about how much room that particular card has.

Container queries answer a better question: how wide is the box this component is inside? A card can switch from a stacked layout to a side-by-side layout when its container is wide enough, wherever you put it. You write the responsive behaviour once, inside the component, and it just works in every context.

Container queries are supported in all modern browsers. In this lesson you'll create containers with container-type, write @container rules, name containers when you nest them, and size things with container query units such as cqi. You'll also see when media queries are still the right tool.

Step 1: Make a container

CSS
.card-wrap { container-type: inline-size; }
  • container-type: inline-size tells the browser to track this element's width (its inline size in left-to-right languages), so its descendants can query it.
  • The container itself can't be styled by its own query; only its children respond.
  • container-type: size tracks height too, but then the element must get its height from somewhere other than its content, so inline-size is what you'll use almost every time.

Step 2: Write an @container rule

CSS
.card { display: grid; gap: 12px; }

@container (min-width: 420px) {
  .card { grid-template-columns: 160px 1fr; }
}

The syntax looks just like a media query. Inside, the conditions refer to the nearest ancestor container. Mobile-first thinking works here too: write the narrow version as the default, then add a wider version inside @container (min-width: ...). Newer syntax also accepts ranges such as @container (width > 420px).

Named containers

When containers are nested, a query uses the closest one. To target a specific ancestor, name it:

CSS
.sidebar { container: sidebar / inline-size; }   /* shorthand: name / type */

@container sidebar (min-width: 300px) {
  .widget { padding: 24px; }
}

The container shorthand sets container-name and container-type together.

Container query units

UnitEquals
cqi1% of the container's inline size (width)
cqb1% of the container's block size (height)
cqw / cqh1% of the container's width / height
cqmin / cqmaxThe smaller / larger of cqi and cqb

They work like viewport units but relative to the container, so font-size: clamp(1rem, 4cqi, 1.75rem) makes a card title scale with the card, not the screen.

CSS Container Queries Syntax

Container queries

.wrap { container-type: inline-size; }
.sidebar { container: sidebar / inline-size; }

@container (min-width: 400px) { .card { display: flex; } }
@container sidebar (width < 300px) { .card { font-size: 0.9rem; } }

.title { font-size: clamp(1rem, 5cqi, 2rem); }

CSS Container Queries Summary

  • Container queries let components respond to their container's size, not the screen's.
  • Create a container with container-type: inline-size.
  • Write @container (min-width: ...) rules for the children.
  • Name containers with container: name / inline-size to target a specific ancestor.
  • cqi units size things relative to the container's width.

CSS Container Queries Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

One card, two containers

The same card HTML and CSS appears in a narrow and a wide container.

.layout { display: grid; grid-template-columns: 200px 1fr; gap: 16px; font-family: sans-serif; }

.wrap { container-type: inline-size; }

.card { display: grid; gap: 10px; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 10px; }
.card img { width: 100%; height: auto; border-radius: 8px; }
.card h3 { margin: 0; }

@container (min-width: 380px) {
  .card { grid-template-columns: 140px 1fr; align-items: center; }
}
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 3Both wrappers become containers.
  2. Line 5By default the card stacks the image above the text.
  3. Lines 9 to 11When its container is at least 380px wide, the card goes side by side. Only the wide copy changes.
Example 2

Container query units

Drag the panel narrower. The title shrinks with its box.

.box {
  container-type: inline-size;
  width: 60%;
  min-width: 200px;
  padding: 16px;
  background: #fef3c7;
  border-radius: 12px;
  font-family: sans-serif;
}

.title {
  font-size: clamp(1.25rem, 9cqi, 3rem);
  margin: 0 0 6px;
}
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 2The box is the container.
  2. Line 3Its width depends on the panel, so it changes as you resize.
  3. Line 12The title is about 9% of the box's width, between 20px and 48px.
Example 3

Named containers in a dashboard

.dash { display: grid; grid-template-columns: 2fr 1fr; gap: 12px; font-family: sans-serif; }
.main { container: main / inline-size; }
.side { container: side / inline-size; }

.stat { display: grid; gap: 4px; padding: 14px; background: #eef2ff; border-radius: 10px; }
.num { font-size: 1.5rem; font-weight: 700; }

@container main (min-width: 300px) {
  .stat { grid-template-columns: auto 1fr; align-items: baseline; gap: 12px; }
  .num { font-size: 2.25rem; }
}
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 2 to 3Two named containers.
  2. Line 8This rule only listens to the main container.
  3. Lines 9 to 10Stats inside main become larger and side by side; the sidebar stat stays compact.

Common CSS Container Queries Mistakes

Querying the container itself

Don't
.card { container-type: inline-size; }
@container (min-width: 400px) { .card { display: flex; } } /* .card can't query itself */
Do
.card-wrap { container-type: inline-size; }
@container (min-width: 400px) { .card { display: flex; } }

Using container-type: size by accident

Don't
.wrap { container-type: size; } /* the box collapses to zero height */
Do
.wrap { container-type: inline-size; }

With size, the container can't take its height from its content.

Forgetting to create a container

Don't
@container (min-width: 400px) { .card { display: flex; } } /* no ancestor has container-type */
Do
.grid > * { container-type: inline-size; }
@container (min-width: 400px) { .card { display: flex; } }

Without a container ancestor, the query never matches.

CSS Container Queries in Real Projects

Container queries in practice

Design systems use container queries so a single card component works in grids, sidebars and modals. Content management systems benefit most, because editors can drop a component into any column. Shopify themes, news sites and dashboards adopted them soon after browsers shipped support in 2023. Combined with cqi units, typography inside components scales naturally.

CSS Container Queries Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Make the wrapper a container that tracks its width.

.wrap {
  container-type: ;
}
Multiple choiceeasy

What does a container query measure?

Multiple choicemedium

What does 10cqi equal?

Multiple choicemedium

When are media queries still the better choice?

Fix the bugmedium

The card should go side by side when its wrapper is at least 300px wide. Fix the container and the query.

.c { container-type: size; display: grid; }
@media (min-width: 300px) {
  .c { grid-template-columns: 1fr 1fr; }
}
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Wrapper is an inline-size container
  • Uses @container
  • Card is side by side

CSS Container Queries Quiz

5 questions to check what you learned.

  1. Which property creates a container?

    • display: container
    • @container
    • position: container
    • container-type
  2. Why are container queries useful for reusable components?

    • They're faster than media queries
    • They replace flexbox
    • The same component adapts to wherever it's placed
    • They work without CSS
  3. What does container: card / inline-size do?

    • Names the container card and sets its type to inline-size
    • Creates a class called card
    • Sets the width to inline
    • Imports a component
  4. With nested containers, which one does an unnamed @container query use?

    • The outermost one
    • The nearest ancestor container
    • The body
    • All of them
  5. Why does container-type: size often cause boxes to collapse?

    • It's a bug
    • It sets display: none
    • It removes padding
    • The container can no longer get its height from its content

CSS Container Queries Challenge

A responsive profile widget

  1. Make .slot an inline-size container named slot
  2. By default, .profile is display: grid with a gap of 8px
  3. In @container slot (min-width: 350px), give .profile grid-template-columns: 80px 1fr
  4. Give .name a font-size of clamp(1rem, 6cqi, 2rem)
.pic { height: 80px; background: #c7d2fe; border-radius: 8px; }
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Named inline-size container
  • Profile is a grid with an 8px gap
  • Wide slot goes side by side
  • Narrow slot stays stacked
  • Name scales with its container