CSS Container Queries

CSS container queries allow styles to respond to the characteristics of a containing element instead of only responding to the viewport. This makes it possible to create reusable components that adapt according to the space available where they are placed.

A card, navigation component, product panel, or other reusable element can change its layout based on the size of its container, allowing the same component to work in different areas of a responsive page.

How Container Queries Work

A media query commonly responds to the viewport. A container size query instead evaluates the dimensions of an ancestor that has been established as a query container.

This is useful when the same component can appear in different parts of a page. A card placed in a narrow sidebar can use one layout while the same card placed in a wider content area can use another.

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

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

The card changes to a two-column layout when its query container reaches the specified width.

Creating a Query Container

Before using a size container query, an ancestor element must be established as an appropriate query container.

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

The container-type property determines which dimensions can be queried.

Descendants of the container can then use an @container rule that responds to the container's size.

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

container-type

The container-type property establishes an element as a query container for size-related container queries.

Value Description
normal The element is not a query container for size queries.
inline-size Allows queries based on the container's inline dimension.
size Allows queries based on both the inline and block dimensions.

For many responsive components, inline-size is the appropriate choice because the component primarily needs to respond to the available horizontal space.

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

@container Rule

The @container at-rule contains CSS that is applied when its container query condition matches.

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

The additional padding is applied when the relevant query container is at least 400 pixels wide.

Like media queries, container queries can change multiple declarations or alter an entire component layout when the condition matches.

Named Containers

The container-name property gives a query container a name. A named container can be targeted by an @container rule.

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

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

Using a container name can make it clear which ancestor a query is intended to use, especially when components are nested inside several possible query containers.

container Shorthand

The container shorthand can set the container name and type in one declaration.

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

The name appears before the slash and the container type appears after it.

This is equivalent to:

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

Container Query Ranges

Container size queries can use minimum and maximum conditions in a form similar to traditional media queries.

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

Modern range syntax can also use comparison operators.

@container (width >= 400px) {
  .card {
    display: flex;
  }
}

A query can also describe a bounded range.

@container (400px <= width <= 700px) {
  .card {
    padding: 2rem;
  }
}

The rule applies when the query container's width falls within the specified range, including both boundaries.

Container Query Units

CSS provides relative length units based on the dimensions of a query container.

Unit Relative To
cqw One percent of the query container's width.
cqh One percent of the query container's height.
cqi One percent of the query container's inline size.
cqb One percent of the query container's block size.
cqmin The smaller of the cqi and cqb values.
cqmax The larger of the cqi and cqb values.
.card h2 {
  font-size: clamp(1.5rem, 6cqi, 3rem);
}

This allows the heading size to respond to the inline size of its query container while the clamp() function limits how small or large the text can become.

Container Queries vs Media Queries

Media queries and container queries solve related but different responsive design problems.

Feature Responds To Common Use
Media Query Viewport, device, or user-related media features Page-level responsive design
Container Query A qualifying ancestor container Component-level responsive design

A media query is useful when the overall page should change according to the viewport.

@media (min-width: 900px) {
  .page {
    grid-template-columns: 2fr 1fr;
  }
}

A container query is useful when a component should respond to the space provided by its own layout context.

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

The two techniques can be used together in the same responsive design.

When to Use Container Queries

Container queries are especially useful for reusable components that may appear in different locations or at different widths.

Situation Possible Use
Card component Switch between stacked and side-by-side content.
Sidebar component Adjust controls according to the sidebar width.
Reusable navigation Change the arrangement when its container provides more space.
Dashboard widget Adapt information density to the widget's available area.

If a responsive change depends on the overall viewport, a media query may be more appropriate. If it depends on the space allocated to a particular component, a container query can make that component more independent and reusable.

CSS Container Query Example

The following example establishes each wrapper as an inline-size query container. The card changes from a stacked layout to two columns when its own container reaches 500 pixels.

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

This allows copies of the same card component to use different layouts on the same page when their containers have different widths.

Open the example in the editor and change the 500px query value. Drag the divider between the code and result panes to change the preview width and see how each component responds to the width of its container.

Play in Editor