# CSS Container Queries: Component-Level Responsive Design

> Learn how CSS container queries enable component-level responsive design — syntax, container types, media query comparisons, and layout examples.

- URL: https://www.browserutils.dev/blog/css-container-queries
- Published: 2026-10-05
- Updated: 2026-07-02

---

CSS container queries let a component respond to the size of its parent container instead of the browser viewport, using an `@container` rule the same way you'd use `@media`. This solves a problem media queries can't: a sidebar card and a main-content card might use the same component, but media queries only know the window size, not how much space that specific container actually has.

For years, responsive design has meant media queries alone — a limitation that forced developers into modifier classes and duplicated breakpoints. Container queries are the missing piece for truly reusable, context-aware components.

## The Problem with Media Queries

Consider a card component that needs to switch between a vertical and horizontal layout. With media queries, you do something like this:

```css
.card {
  display: flex;
  flex-direction: column;
}

@media (min-width: 768px) {
  .card {
    flex-direction: row;
  }
}
```

This works when the card is full-width. But what happens when the same card sits inside a narrow sidebar? At 1200px viewport width, the media query triggers the horizontal layout — even though the sidebar only gives the card 300px of space. The card looks broken.

You end up writing modifier classes (`.card--sidebar`), duplicating breakpoints, or using JavaScript to measure containers. None of these solutions are clean.

## Container Queries: The Basics

Container queries flip the model. Instead of asking "how wide is the viewport?", a component asks "how wide is my container?"

### Step 1: Define a Container

First, designate an element as a containment context:

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

Or use the shorthand:

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

### Step 2: Query the Container

Then write style rules that respond to the container's size:

```css
.card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

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

@container card-container (min-width: 700px) {
  .card {
    flex-direction: row;
    gap: 2rem;
  }

  .card__image {
    flex: 0 0 40%;
  }
}
```

Now the card responds to its actual available space. Put it in a sidebar — it stays vertical. Put it in the main content area — it goes horizontal. No modifier classes, no JavaScript.

## Container Types

The `container-type` property determines what can be queried:

| Value | What You Can Query |
|---|---|
| `inline-size` | Width (in horizontal writing modes) |
| `size` | Both width and height |
| `normal` | No size queries (default). Only style queries work. |

In most cases, `inline-size` is what you want. Querying both dimensions with `size` has stricter containment requirements and is rarely needed.

### What Containment Does

When you set `container-type: inline-size`, the browser applies **layout containment** and **inline-size containment** to the element. This means:

- The element's inline size cannot depend on its children (it must be determined by its own constraints)
- The browser can optimize rendering because changes inside the container do not affect its size

This is why you cannot make any element a container. The element must have an independently determinable size — it cannot rely on its content for width.

## Container Query Syntax

Container queries support the same comparison operators as media queries:

```css
/* Minimum width */
@container (min-width: 400px) { ... }

/* Maximum width */
@container (max-width: 600px) { ... }

/* Range syntax */
@container (400px <= width <= 800px) { ... }

/* Height queries (requires container-type: size) */
@container (min-height: 300px) { ... }

/* Combining conditions */
@container (min-width: 400px) and (max-width: 800px) { ... }
```

### Named vs Unnamed Containers

If you use `@container` without a name, it queries the **nearest ancestor** with containment:

```css
.wrapper {
  container-type: inline-size;
}

/* Queries the nearest container ancestor */
@container (min-width: 500px) {
  .card { flex-direction: row; }
}
```

Named containers let you target a specific ancestor:

```css
.sidebar {
  container: sidebar / inline-size;
}

.main {
  container: main-content / inline-size;
}

/* Only responds to the sidebar container */
@container sidebar (min-width: 300px) {
  .widget { display: grid; grid-template-columns: 1fr 1fr; }
}
```

Use named containers when you have nested containers or need to be explicit about which one you are targeting.

## Container Query Units

Container queries introduce new CSS units relative to the container's dimensions:

| Unit | Relative To |
|---|---|
| `cqw` | 1% of container width |
| `cqh` | 1% of container height |
| `cqi` | 1% of container inline size |
| `cqb` | 1% of container block size |
| `cqmin` | Smaller of `cqi` and `cqb` |
| `cqmax` | Larger of `cqi` and `cqb` |

```css
.card__title {
  font-size: clamp(1rem, 4cqi, 2rem);
}

.card__image {
  height: 30cqb;
}
```

These units let typography and spacing scale with the container, not the viewport.

## Practical Examples

### Responsive Card Component

```css
.card-grid {
  container-type: inline-size;
  display: grid;
  gap: 1.5rem;
}

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  overflow: hidden;
}

.card__body {
  padding: 1rem;
}

.card__image {
  aspect-ratio: 16 / 9;
  object-fit: cover;
  width: 100%;
}

/* When the container is wide enough, go horizontal */
@container (min-width: 500px) {
  .card {
    flex-direction: row;
  }

  .card__image {
    width: 200px;
    aspect-ratio: 1;
  }
}

/* At larger sizes, add more detail */
@container (min-width: 700px) {
  .card__image {
    width: 280px;
  }

  .card__body {
    padding: 1.5rem;
  }

  .card__excerpt {
    display: block;  /* Hidden at smaller sizes */
  }
}
```

### Adaptive Navigation

```css
.nav-wrapper {
  container-type: inline-size;
}

.nav {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.nav__label {
  display: none;
}

/* Show labels when there's room */
@container (min-width: 200px) {
  .nav {
    flex-direction: column;
  }
  .nav__label {
    display: inline;
  }
}

/* Switch to horizontal layout */
@container (min-width: 600px) {
  .nav {
    flex-direction: row;
    gap: 1.5rem;
  }
}
```

### Dashboard Widgets

```css
.dashboard-cell {
  container-type: inline-size;
}

.widget {
  padding: 1rem;
}

.widget__chart {
  height: 150px;
}

.widget__stats {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.5rem;
}

@container (min-width: 350px) {
  .widget__stats {
    grid-template-columns: 1fr 1fr;
  }

  .widget__chart {
    height: 200px;
  }
}

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

  .widget__chart {
    height: 300px;
  }
}
```

When building these layouts, the [CSS grid generator](/tools/css-grid-generator) can help you prototype grid configurations quickly — see our [advanced CSS Grid guide](/blog/css-grid-advanced) for subgrid and complex layout patterns. For flex-based layouts within your containers, the [CSS flexbox generator](/tools/css-flexbox-generator) lets you experiment with different flex properties visually.

## Container Queries vs Media Queries

Container queries do not replace media queries. They serve different purposes:

| Aspect | Media Queries | Container Queries |
|---|---|---|
| Responds to | Viewport size | Container size |
| Best for | Page-level layout | Component-level layout |
| Use case | Navigation, page grid | Cards, widgets, embedded components |
| Context awareness | None | Full |
| Browser support | Universal | Modern browsers (2023+) |

Use media queries for your page shell — the overall layout, navigation, and major sections. Use container queries for components that need to adapt to wherever they are placed.

A common pattern is combining both:

```css
/* Media query for page layout */
@media (min-width: 768px) {
  .page {
    display: grid;
    grid-template-columns: 300px 1fr;
  }
}

/* Container query for component layout */
.content-area {
  container-type: inline-size;
}

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

## Style Queries

Container queries can also query custom property values, not just dimensions:

```css
.card-wrapper {
  container-type: normal;
  --theme: light;
}

@container style(--theme: dark) {
  .card {
    background: #1f2937;
    color: #f9fafb;
  }
}
```

Style queries are still gaining browser support but offer exciting possibilities for theme-aware components.

## Best Practices

1. **Set container-type on wrapper elements**, not on the component itself. A component cannot be its own container.

2. **Prefer inline-size** over `size` unless you genuinely need height-based queries. The containment requirements for `size` are stricter.

3. **Name your containers** when nesting. Unnamed queries find the nearest ancestor container, which can be surprising in complex layouts.

4. **Start mobile-first**. Define the base styles for the smallest container size and add container queries for larger sizes.

5. **Do not nest containers unnecessarily**. Each containment context adds constraints. Only add containment where components genuinely need to adapt.

6. **Test at multiple container widths**, not just viewport widths. Resize the actual container element in DevTools to verify behavior.

## Summary

Container queries bring responsive design to the component level. Instead of checking the viewport, components respond to their actual available space. This makes components truly portable — the same card component works in a full-width layout, a sidebar, or a dashboard grid without any modifications. Combined with media queries for page-level layout, container queries complete the responsive design toolkit that CSS has needed for years.