2026-04-05web-dev[intermediate][explainer]

CSS Container Queries: The Component-First Responsive Revolution

Container queries let components respond to their own size rather than viewport width, enabling truly modular responsive design. With 95%+ browser support in 2026, they're ready for production use.

The responsive web has been stuck in a viewport-centric paradigm for over a decade. In the early 2020s, we used Media Queries based on the viewport size (e.g., @media (max-width: 768px)). But a component doesn't know how big the viewport is; it only knows how much space it has in its parent container.

Container Queries allow us to define styles based on the Container's Size, making our components truly portable. A card component in 2026 can be a full-width hero on one page and a tiny thumbnail in a sidebar on another all using the same CSS class.

The Container Query Syntax

Container queries require two steps: declaring a containment context and querying it.

/* Step 1: Establish the container */
.card-container {
  container-type: inline-size; /* Creates a query container */
}

/* Step 2: Query the container */
@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 1.5rem;
  }
}

To use container size queries, you need to declare a containment context on an element so that the browser knows you might want to query the dimensions of this container later. To do this, use the container-type property with a value of size, inline-size, or normal.

The container-type values work as follows:

  • inline-size: The query will be based on the inline dimensions of the container. Applies layout, style, and inline-size containment to the element.
  • size: The query will be based on the inline and block dimensions of the container. Applies layout, style, and size containment to the container.
  • normal: The element is not a query container for any container size queries, but remains a query container for container style queries.

Named Containers and Nesting

When dealing with nested containers, use container-name to be explicit about which container you're targeting:

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

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

/* Target specific containers */
@container sidebar (min-width: 250px) {
  .widget { display: block; }
}

@container article (min-width: 600px) {
  .widget { display: flex; }
}

Name your containers with container-name when nesting to be explicit about which container you are querying.

Container Query Units

Container queries come with their own unit system, similar to viewport units but scoped to the container:

  • cqw: 1% of container's width
  • cqh: 1% of container's height
  • cqi: 1% of container's inline size
  • cqb: 1% of container's block size
  • cqmin: Smaller of cqi and cqb
  • cqmax: Larger of cqi and cqb
.card {
  padding: 2cqi; /* Padding scales with container */
  font-size: clamp(1rem, 4cqi, 2rem);
}

Container query length units are also fully supported.

Style Queries: The Next Frontier

Beyond size queries, CSS also supports style queries that respond to computed styles. Container style queries are still only partially supported, but they're powerful:

@container style(--theme: dark) {
  .card {
    background: var(--dark-bg);
    color: var(--dark-text);
  }
}

Style queries (@container style()) are more limited: Chrome 111+ and Edge 111+ only, with Firefox and Safari still developing support.

Browser Support and Migration

Size container queries are supported in Chrome 105+, Firefox 110+, Safari 16+, and Edge 105+ — over 95% global coverage in 2026.

For migration from media queries:

Identify components that appear in multiple layout contexts (cards, widgets, navigation). Add container-type: inline-size to their parent wrappers. Convert each component's @media rules to @container rules, adjusting breakpoint values since container widths are smaller than viewport widths.

Use @supports for progressive enhancement so older browsers fall back to media queries gracefully.

@supports (container-type: inline-size) {
  .card-container {
    container-type: inline-size;
  }
  
  @container (min-width: 400px) {
    .card { display: grid; }
  }
}

@supports not (container-type: inline-size) {
  @media (min-width: 768px) {
    .card { display: grid; }
  }
}

Pro Tip

Understand when viewport-based media queries remain preferable (global layout adjustments) versus container queries (component-scoped styles). Media queries: Better for broad, device or viewport-level responsive adjustments such as global navigations or page layout changes. Container queries: Ideal for modular components that need to respond based on the space they occupy, supporting encapsulated, reusable design across different contexts. Don't replace all media queries—use them together strategically.

Example: Adaptive Card Component

.card-grid {
  container-type: inline-size;
  display: grid;
  gap: 1rem;
}

.card {
  background: white;
  border-radius: 8px;
  padding: 1rem;
  display: flex;
  flex-direction: column;
}

.card__image {
  width: 100%;
  height: 200px;
  object-fit: cover;
  border-radius: 4px;
}

.card__content {
  padding: 1rem 0;
}

.card__title {
  font-size: 1.2rem;
  margin: 0 0 0.5rem 0;
}

.card__description {
  color: #666;
  font-size: 0.9rem;
  line-height: 1.4;
}

/* Container-based adaptations */
@container (min-width: 400px) {
  .card {
    flex-direction: row;
    align-items: flex-start;
  }
  
  .card__image {
    width: 120px;
    height: 120px;
    margin-right: 1rem;
    flex-shrink: 0;
  }
  
  .card__content {
    padding: 0;
    flex: 1;
  }
}

@container (min-width: 600px) {
  .card {
    padding: 1.5rem;
  }
  
  .card__image {
    width: 160px;
    height: 160px;
  }
  
  .card__title {
    font-size: 1.4rem;
  }
  
  .card__description {
    font-size: 1rem;
  }
}

/* Responsive grid using container units */
.card-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100cqi), 1fr));
}

This card component adapts its layout based on available space, not viewport size. Drop it into a narrow sidebar and it stays vertical. Place it in a wide content area and it becomes horizontal. This is what makes CSS Container Queries so powerful: you can quite literally drop this panel into any project and the layout will respond as it should, as it's based on the space it is in rather than the size of the browser's viewport.