Skip to main content
Ganesh Joshi
Back to Blogs

CSS container queries: responsive design without media queries

February 15, 20264 min read
Tutorials
CSS or layout on screen

Media queries respond to the viewport, so the same component can look wrong when placed in a narrow sidebar versus a wide main column. Container queries solve this by letting you style an element based on the size of its container.

The problem with media queries

Consider a card component with media queries:

.card {
  display: block;
}

@media (min-width: 600px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}

This card switches to a two-column layout at 600px viewport width. But what if the card is in a 300px sidebar? It still uses the two-column layout because the viewport is wide, not because the card has space.

How container queries work

Container queries check the size of a container element, not the viewport:

1. Define a container

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

2. Query the container

@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}

Now the card switches layout when its wrapper is at least 400px wide, regardless of viewport size.

Container types

Value Description
inline-size Query inline dimension (width in horizontal mode)
size Query both inline and block dimensions
normal No containment (default)

Use inline-size for most cases. size is needed only when querying height, which can cause layout issues.

.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

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

Named containers

Name containers to target them explicitly:

.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

@container sidebar (min-width: 200px) {
  .sidebar-card {
    padding: 1.5rem;
  }
}

@container sidebar (max-width: 199px) {
  .sidebar-card {
    padding: 0.75rem;
  }
}

Without names, @container queries the nearest ancestor container.

Container query syntax

/* Min-width */
@container (min-width: 400px) { }

/* Max-width */
@container (max-width: 399px) { }

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

/* Named container */
@container sidebar (min-width: 200px) { }

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

Container query units

Use container-relative units for sizing:

Unit Description
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 or cqb
cqmax Larger of cqi or cqb
.card-title {
  font-size: clamp(1rem, 5cqi, 2rem);
}

.card-image {
  width: 50cqi;
}

These units scale with the container, not the viewport.

Practical examples

Responsive card

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

.card {
  display: flex;
  flex-direction: column;
  padding: 1rem;
}

.card-image {
  width: 100%;
  aspect-ratio: 16/9;
}

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

  .card-image {
    width: 40%;
  }
}

@container (min-width: 600px) {
  .card {
    padding: 2rem;
  }

  .card-title {
    font-size: 1.5rem;
  }
}

Adaptive navigation

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

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

.nav-label {
  display: none;
}

@container (min-width: 200px) {
  .nav-items {
    flex-direction: row;
    flex-wrap: wrap;
  }

  .nav-label {
    display: inline;
  }
}

Grid that adapts to container

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

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

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

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

Container queries vs media queries

Aspect Media queries Container queries
Based on Viewport size Container size
Component reuse Same everywhere Adapts to context
Use case Page layout Component layout
Nesting N/A Queries nearest container

When to use each

Container queries:

  • Card components
  • Sidebar widgets
  • Reusable UI components
  • Embedded content
  • Any component that appears in multiple contexts

Media queries:

  • Page-level layout changes
  • Navigation bar structure
  • Overall grid columns
  • Print styles

You can combine both:

/* Page layout with media query */
@media (min-width: 768px) {
  .page {
    display: grid;
    grid-template-columns: 250px 1fr;
  }
}

/* Component adapts to its container */
.widget-wrapper {
  container-type: inline-size;
}

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

Browser support and fallbacks

Container queries are supported in all modern browsers. Provide a default layout for older browsers:

/* Default (works everywhere) */
.card {
  display: block;
}

/* Enhanced (container query) */
@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}

Older browsers ignore @container and keep the default.

Performance considerations

Container queries add layout calculations. Best practices:

  1. Keep containers close to the element you are styling
  2. Avoid deeply nested container queries
  3. Use inline-size instead of size when possible
  4. Test performance with many components on page

Summary

Container queries make components truly reusable:

  1. Define containers with container-type: inline-size
  2. Name containers for explicit targeting
  3. Query containers with @container (min-width: x)
  4. Use container units like cqi for relative sizing
  5. Combine with media queries for page-level layout

The MDN container queries guide has the full specification and examples.

Frequently Asked Questions

Container queries let you style an element based on the size of its container, not the viewport. This makes components truly reusable since they adapt to their context.

Media queries respond to viewport size, so the same component looks the same everywhere. Container queries respond to the component's container, so a card in a sidebar adapts differently than the same card in a wide column.

container-type defines an element as a query container. Use 'inline-size' to query width (most common), 'size' for both dimensions, or 'normal' to disable.

Yes, container queries are supported in all modern browsers (Chrome, Firefox, Safari, Edge). They are safe to use in production with a fallback default style.

Use container queries for reusable components that should adapt to their context. Use media queries for page-level layout changes that depend on viewport size.

Related Posts