Skip to main content

Container Queries: Component-Level Responsiveness

Container queries are the biggest shift in responsive CSS since media queries. Instead of responding to the viewport width, they respond to the size of a parent element — making truly reusable, context-aware components possible.

1. The Problem They Solve

With media queries, a component like .card has no idea whether it's in a narrow sidebar or a wide main column. Container queries let it adapt to its actual container:

Without container queries: With container queries:
┌──────────────────────────────┐ ┌────────────────────────────────────┐
│ Sidebar │ Main Content │ │ Sidebar │ Main Content │
│ .card │ .card │ │ ┌────────┐ │ ┌─────────┐ │
│ ┌──────┐ │ ┌──────────┐ │ │ │Image │ │ │Image │ │
│ │IMG │ │ │IMG │ │ │ │──────-│ │ │ │ │
│ │The │ │ │ │ │ │ │Title │ │ │─────────│ │
│ │title │ │ │Title │ │ │ └────────┘ │ │Title │ │
│ │long │ │ │ │ │ │ (narrow) │ │ │ │
│ └──────┘ │ └──────────┘ │ │ │ └─────────┘ │
│ (same layout regardless) │ │ (adapts to container width!) │
└──────────────────────────────┘ └────────────────────────────────────┘

2. Enabling Container Queries

Step 1: Define a containment context on the parent element:

/* The container — this is the element the query measures */
.card-wrapper {
container-type: inline-size; /* Measure horizontal size */
container-name: card; /* Optional: name it for specificity */
}

Step 2: Write your @container rule:

/* Default: narrow/stacked layout */
.card {
display: flex;
flex-direction: column;
}

/* When the container is wide enough: horizontal layout */
@container card (min-width: 400px) {
.card {
flex-direction: row;
}
.card__image {
width: 200px;
flex-shrink: 0;
}
}

3. container-type Values

ValueWhat It Measures
inline-sizeWidth only — most common, safest
block-sizeHeight only — use rarely
sizeBoth width and height
normal(Default) No containment — required to reset

[!NOTE] Use inline-size instead of size unless you specifically need height-based queries — size has stricter performance implications and requires the element have an explicit height.

4. container-name — Multiple Containers

Name your containers to target specific ones in nested structures:

.sidebar { container-type: inline-size; container-name: sidebar; }
.main-content { container-type: inline-size; container-name: main; }
.card-list { container-type: inline-size; container-name: card-list; }

/* Target specific containers */
@container sidebar (max-width: 300px) {
.nav-item { flex-direction: column; }
}

@container main (min-width: 800px) {
.post-grid { grid-template-columns: repeat(3, 1fr); }
}

5. Container Query Units

cq* units are relative to the container — similar to vw/vh but for the container:

UnitRelative To
cqw1% of container width
cqh1% of container height
cqi1% of container inline size
cqb1% of container block size
cqminSmaller of cqi or cqb
cqmaxLarger of cqi or cqb
/* Font scales with the container, not the viewport */
@container (min-width: 300px) {
.card__title { font-size: clamp(1rem, 5cqi, 2rem); }
}

6. Real World: Adaptive Card Component

<div class="card-wrapper">
<article class="card">
<div class="card__media">
<img src="..." alt="...">
</div>
<div class="card__body">
<h2 class="card__title">Title</h2>
<p class="card__excerpt">Excerpt text...</p>
</div>
</article>
</div>
/* Container context */
.card-wrapper { container-type: inline-size; container-name: card; }

/* Default: vertical stack (narrow) */
.card { display: flex; flex-direction: column; gap: 0; }
.card__media img { width: 100%; aspect-ratio: 16/9; object-fit: cover; }

/* Medium card: horizontal layout */
@container card (min-width: 380px) {
.card { flex-direction: row; }
.card__media { width: 140px; flex-shrink: 0; }
.card__media img { height: 100%; aspect-ratio: auto; }
}

/* Wide card: extra info, larger font */
@container card (min-width: 600px) {
.card__title { font-size: 1.5rem; }
.card__excerpt { display: block; } /* Was hidden in narrow layout */
.card__meta { display: flex; } /* Show date/author row */
}

7. Real World: Responsive Grid Without Breakpoints

.post-grid { container-type: inline-size; }

.post-grid .posts {
display: grid;
gap: 1.5rem;
grid-template-columns: 1fr; /* 1 col default */
}

@container (min-width: 500px) {
.post-grid .posts { grid-template-columns: repeat(2, 1fr); }
}

@container (min-width: 800px) {
.post-grid .posts { grid-template-columns: repeat(3, 1fr); }
}

Now this grid adapts whether it's in a sidebar, a tabs panel, or full-width — no more viewport breakpoints needed.

8. Container Queries vs Media Queries

Use CaseUse
Global layout (sidebar on/off)Media Query
Component adapts to its contextContainer Query
Typography based on viewportMedia Query or clamp()
Card layout in variable columnsContainer Query
Print stylesMedia Query
Dark mode preferenceMedia Query

[!TIP] The rule of thumb: If you're styling a page structure, use media queries. If you're styling a component, use container queries. Most components benefit from container queries over media queries.

9. WordPress: Container Queries in GeneratePress

/* Wrap the widget area with a container context */
.widget-area { container-type: inline-size; container-name: widget-area; }

@container widget-area (max-width: 300px) {
.widget { padding: 1rem; }
.widget-title { font-size: 1rem; }
}

/* Bricks Builder container query */
.brxe-container { container-type: inline-size; }
@container (min-width: 500px) {
.brxe-block { flex-direction: row; }
}