Skip to main content

Container Queries: Component-Based Responsive Design in 2026

Created: March 7, 2026 CalmOps 10 min read

Introduction

For over a decade, responsive web design has relied on media queries based on the viewport—the browser window size. This approach works well for page-level layouts but breaks down when building reusable components that appear in various contexts. A navigation component might look perfect in a full-width header but completely break when placed in a narrow sidebar. Container queries solve this fundamental limitation by allowing styles to respond to a component’s container size, not the viewport.

The CSS Container Queries specification has achieved broad browser support in 2026, making it a practical choice for production applications. This capability fundamentally changes how we think about component architecture, enabling truly self-contained responsive components that adapt to any context they’re placed in.

This guide covers everything from basic setup to advanced patterns, helping you build robust component libraries that work at any size.

Understanding Container Queries

Container queries extend the familiar media query syntax but target element containers instead of the viewport.

The Core Problem

Traditional responsive design uses viewport-based media queries:

/* This card looks great full-width but breaks in narrow contexts */
.card {
  display: grid;
  grid-template-columns: 200px 1fr;
}

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

When this card appears in a 300px sidebar, the media query still applies because the viewport might be 1200px, even though the card has only 300px of space. The card’s layout becomes wrong for its actual context.

Container Queries Solution

Container queries solve this by making styles respond to container size:

/* Define a containment context */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* Query the container instead of viewport */
@container card (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}

@container card (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}

Now the card adapts based on its own container size, regardless of where it appears in the page.

Container Types

The container-type property defines what aspects of the container are queryable:

/* Containment for inline size (width) only */
.container-inline {
  container-type: inline-size;
}

/* Containment for block size (height) only */
.container-block {
  container-type: block-size;
}

/* Containment for both dimensions */
.container-both {
  container-type: size;
}

/* No containment (default) */
.container-none {
  container-type: normal;
}

For most responsive design needs, inline-size suffices—it queries the container’s width regardless of viewport width.

Setting Up Containers

Proper container setup is essential for container queries to work correctly.

Basic Setup

Create a containment context with CSS:

.widget-container {
  container-type: inline-size;
  container-name: widget;
}
<div class="widget-container">
  <div class="widget">
    <!-- Widget content that responds to container -->
  </div>
</div>

The container element must have explicit containment for the queries to work.

Containment Properties

Containment improves performance and enables the query behavior:

.card-wrapper {
  /* Creates a containing block for descendants */
  contain: layout style;
  
  /* Also make it queryable */
  container-type: inline-size;
  container-name: card;
}

The contain property tells the browser to limit how much changes inside the container affect the rest of the page. This isolation is what makes container queries practical.

Naming Containers

Name containers to query specific ancestors:

<main class="main-content" style="container-name: main;">
  <aside class="sidebar" style="container-name: sidebar;">
    <div class="widget">
      <!-- This queries the sidebar, not main -->
    </div>
  </aside>
</main>
/* Query the sidebar specifically */
@container sidebar (min-width: 300px) {
  .widget {
    /* Styles when in sidebar */
  }
}

/* Query the main content */
@container main (min-width: 800px) {
  .widget {
    /* Styles when in main area */
  }
}

Named containers enable targeting specific parent contexts.

Writing Container Queries

The syntax mirrors media queries with minor differences.

Querying Container Width

The most common query checks width:

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

@container (max-width: 399px) {
  .component {
    flex-direction: column;
  }
}

Querying Container Height

For height-based layouts, use block-size:

@container (min-height: 200px) {
  .component {
    display: grid;
    grid-template-rows: 1fr auto;
  }
}

@container (max-height: 199px) {
  .component {
    display: flex;
    flex-direction: row;
    align-items: center;
  }
}

Container Query Units

Container-relative units respond to container size:

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
.component-title {
  /* Title scales with container */
  font-size: clamp(1rem, 5cqi, 2rem);
}

.component {
  /* Padding based on container */
  padding: calc(1cqi * 0.5);
}

These units eliminate the need for breakpoints in many cases.

Logical Properties

Use logical properties for internationalization:

@container (min-inline-size: 400px) {
  .component {
    /* Inline dimension = width in horizontal writing */
    flex-direction: row;
  }
}

@container (max-inline-size: 399px) {
  .component {
    flex-direction: column;
  }
}

Practical Component Patterns

Container queries shine in real-world component scenarios.

Responsive Cards

Build cards that adapt anywhere:

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

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

.card-image {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.card-content {
  padding: 16px;
}

/* Large card - side-by-side layout */
@container card (min-width: 400px) {
  .card {
    flex-direction: row;
  }
  
  .card-image {
    width: 40%;
    height: auto;
  }
  
  .card-content {
    width: 60%;
  }
}

/* Medium card - stacked with larger image */
@container card (min-width: 300px) and (max-width: 399px) {
  .card-image {
    height: 180px;
  }
  
  .card-content {
    padding: 20px;
  }
}

/* Small card - compact */
@container card (max-width: 299px) {
  .card-image {
    height: 120px;
  }
  
  .card-content {
    padding: 12px;
  }
  
  .card-title {
    font-size: 1rem;
  }
}

Navigation that adapts to any space:

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

.nav-links {
  display: flex;
  gap: 16px;
}

/* Full navigation - horizontal */
@container nav (min-width: 600px) {
  .nav-links {
    flex-direction: row;
    justify-content: flex-end;
  }
  
  .nav-item {
    padding: 8px 16px;
  }
  
  .nav-logo {
    margin-right: auto;
  }
}

/* Medium - compact horizontal */
@container nav (min-width: 400px) and (max-width: 599px) {
  .nav-links {
    gap: 8px;
  }
  
  .nav-item {
    padding: 6px 12px;
    font-size: 14px;
  }
}

/* Small - wrap */
@container nav (max-width: 399px) {
  .nav-links {
    flex-wrap: wrap;
    justify-content: center;
  }
  
  .nav-logo {
    width: 100%;
    text-align: center;
    margin-bottom: 12px;
  }
}

Responsive Images

Images that scale intelligently:

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

.image-wrapper img {
  width: 100%;
  height: auto;
  display: block;
}

/* Large - full display */
@container image-wrapper (min-width: 500px) {
  .image-wrapper img {
    object-fit: cover;
    aspect-ratio: 16/9;
  }
}

/* Medium - square */
@container image-wrapper (min-width: 300px) and (max-width: 499px) {
  .image-wrapper img {
    object-fit: cover;
    aspect-ratio: 1;
  }
}

/* Small - tall */
@container image-wrapper (max-width: 299px) {
  .image-wrapper img {
    object-fit: cover;
    aspect-ratio: 3/4;
  }
}

Form Components

Forms that work at any width:

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

.form-field {
  margin-bottom: 16px;
}

.form-label {
  display: block;
  margin-bottom: 4px;
  font-weight: 500;
}

.form-input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

/* Wide form - horizontal fields */
@container form (min-width: 500px) {
  .form-row {
    display: flex;
    gap: 16px;
  }
  
  .form-field {
    flex: 1;
  }
}

/* Narrow form - stacked */
@container form (max-width: 499px) {
  .form-row {
    display: block;
  }
}

Combining with Other Techniques

Container queries work alongside media queries and other CSS features.

Viewport + Container Queries

Use both for comprehensive responsive design:

/* Global layout based on viewport */
@media (max-width: 768px) {
  .page-layout {
    grid-template-columns: 1fr;
  }
}

@media (min-width: 769px) {
  .page-layout {
    grid-template-columns: 250px 1fr;
  }
}

/* Components based on their containers */
.component-container {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .component {
    /* Component adapts regardless of page layout */
  }
}

Container Queries + Grid

Powerful layouts combining both:

.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
}

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

@container (min-width: 350px) {
  .dashboard-card {
    padding: 24px;
  }
}

@container (max-width: 349px) {
  .dashboard-card {
    padding: 12px;
  }
}

CSS Custom Properties

Combine containers with custom properties:

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

.card {
  /* Use container query units with custom properties */
  --padding: calc(10cqi * 0.04);
  padding: var(--padding);
  font-size: clamp(0.875rem, 2cqi, 1.125rem);
}

@container card (min-width: 300px) {
  .card {
    --padding: 20px;
  }
}

Browser Support and Fallbacks

Container queries have excellent support in modern browsers, but fallbacks ensure broader compatibility.

Browser Support

As of 2026, container queries are supported in:

  • Chrome 105+
  • Firefox 110+
  • Safari 16+
  • Edge 105+

Most modern projects can use container queries directly.

Feature Detection

Detect support with @supports:

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

/* Fallback for browsers without container queries */
@supports not (container-type: inline-size) {
  .card {
    /* Traditional responsive styles */
    display: grid;
    grid-template-columns: 200px 1fr;
  }
  
  @media (max-width: 400px) {
    .card {
      grid-template-columns: 1fr;
    }
  }
}

/* Container query styles */
@supports (container-type: inline-size) {
  @container (min-width: 400px) {
    .card {
      display: grid;
      grid-template-columns: 200px 1fr;
    }
  }
  
  @container (max-width: 399px) {
    .card {
      grid-template-columns: 1fr;
    }
  }
}

Graceful Degradation

Design for fallbacks rather than blocking features:

.card-container {
  /* Works even without container queries */
  display: flex;
  flex-direction: column;
  
  /* Enhanced with container queries */
  container-type: inline-size;
}

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

Advanced Patterns

More sophisticated patterns for complex applications.

Nested Containers

Containers can nest, with inner queries using outer containers:

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

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

.widget {
  /* Queries widget container */
}

@container section (max-width: 600px) {
  .widget {
    /* Override when in narrow section */
  }
}

Aspect Ratio Containers

Create aspect-ratio-based containers:

.aspect-container {
  container-type: size;
  container-name: aspect;
  aspect-ratio: 16/9;
}

.content {
  width: 100%;
  height: 100%;
}

@container aspect (aspect-ratio < 1) {
  .content {
    /* Portrait orientation adjustments */
  }
}

@container aspect (aspect-ratio > 2) {
  .content {
    /* Ultra-wide adjustments */
  }
}

Container Style Queries

Query computed styles with style queries:

.theme-container {
  container-type: inline-size;
  container-name: theme;
  --theme: light;
}

@container theme style(--theme: dark) {
  .component {
    background: #1a1a1a;
    color: white;
  }
}

@container theme style(--theme: light) {
  .component {
    background: white;
    color: #1a1a1a;
  }
}

Browser support for style queries is still emerging.

Performance Considerations

Container queries are highly performant, but understanding optimization helps.

Containment Benefits

The contain property provides performance benefits:

.container {
  /* Layout containment prevents reflows from affecting rest of page */
  contain: layout style;
  
  /* Makes container queryable */
  container-type: inline-size;
}

Minimizing Recalculations

Large numbers of container queries can impact performance:

/* Efficient - discrete breakpoints */
@container (max-width: 300px) { /* styles */ }
@container (min-width: 301px) and (max-width: 500px) { /* styles */ }
@container (min-width: 501px) { /* styles */ }

/* Less efficient - many overlapping queries */
@container (min-width: 100px) { /* styles */ }
@container (min-width: 150px) { /* styles */ }
@container (min-width: 200px) { /* styles */ }

Debugging Container Queries

Browser dev tools highlight containers:

/* Visual indicator during development */
.debug-container {
  container-type: inline-size;
  outline: 2px dashed red;
}

Remove debug styles in production.

Conclusion

Container queries represent a paradigm shift in responsive design. Rather than designing responsive components that happen to work in different page layouts, we can now design truly self-contained components that adapt intelligently to any space they’re given.

The key insight is that components should respond to their context, not the viewport. A card in a sidebar should look different from the same card in main content—not because of where it is in the page structure, but because of how much space it has available.

Start using container queries for new components, particularly those designed for reuse. The combination of container queries, CSS Grid, and modern CSS features enables component architectures that were previously impossible without JavaScript.

As browser support matures and developer familiarity grows, container queries will become as fundamental to responsive design as media queries are today. Building this capability into your workflow prepares you for the next era of component-based web development.

Resources

Comments

Share this article

Scan to read on mobile