🚀AdvancedAdvanced Responsive Design

CSS Container Queries

Style components based on their own container size rather than the viewport, enabling truly portable responsive components.

Overview

Container queries let you apply styles based on the size of a containing element rather than the viewport. This makes components truly self-contained and reusable in any layout context. ```css /* 1. Mark the container */ .card-wrapper { container-type: inline-size; container-name: card; } /* 2. Query the container */ @container card (min-width: 400px) { .card { display: flex; flex-direction: row; } } ``` **container-type values:** - `inline-size` queries width (most common) - `size` queries width and height - `normal` participates in style queries only **Shorthand:** ```css .wrapper { container: card / inline-size; /* name / type */ } ``` **Container query units:** - `cqi` 1% of container inline size - `cqb` 1% of container block size - `cqw` 1% of container width - `cqh` 1% of container height - `cqmin` 1% of smaller dimension - `cqmax` 1% of larger dimension

Key Points

  • •container-type: inline-size enables width-based queries on a parent element
  • •container-name gives the container an identifier so nested containers can be targeted specifically
  • •Container queries use the same range syntax as media queries: (width > 400px)
  • •cqi and cqb units scale relative to the container, not the viewport
  • •An element cannot query itself, only its ancestor containers
  • •Multiple container names can be assigned: container-name: card sidebar
  • •Style queries (@container style()) can query custom property values on a container
  • •Supported in Chrome 105+, Firefox 110+, Safari 16+ covering all modern browsers

Examples

Basic container query for a card component

/* The wrapper becomes a container */
.card-wrapper {
  container-type: inline-size;
}

/* Default: stacked layout */
.card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  background: white;
}

/* Wide container: switch to row layout */
@container (min-width: 480px) {
  .card {
    flex-direction: row;
    align-items: center;
  }
  .card-image {
    width: 140px;
    flex-shrink: 0;
  }
}

The card switches between stacked and side-by-side based on the card wrapper width, not the viewport.

Named containers for precise targeting

/* Name each container */
.sidebar {
  container: sidebar / inline-size;
}

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

/* Same component, different behaviour per context */
@container sidebar (max-width: 240px) {
  .widget {
    font-size: 0.8rem;
    padding: 8px;
  }
}

@container main (min-width: 600px) {
  .widget {
    font-size: 1rem;
    padding: 20px;
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

Named containers let the same component adapt differently depending on which container it lives in.

Container query units (cqi)

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

.hero-title {
  /* Font scales with the container width */
  font-size: clamp(1.5rem, 8cqi, 4rem);
  line-height: 1.1;
}

.hero-body {
  font-size: clamp(0.9rem, 3cqi, 1.25rem);
}

/* Column count based on container */
@container (min-width: 600px) {
  .feature-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

8cqi means 8% of the container inline size, making typography scale with component width rather than viewport width.

Style queries (querying custom property values)

/* Mark the container */
.theme-wrapper {
  container-type: normal;
}

/* Query the custom property value */
@container style(--theme: dark) {
  .card {
    background: #1e293b;
    color: #f1f5f9;
    border-color: #334155;
  }
}

@container style(--theme: accent) {
  .card {
    background: #eef2ff;
    border-color: #6366f1;
    color: #4338ca;
  }
}

/* Apply theme by setting the variable on the wrapper */
.dark-section {
  --theme: dark;
}

Common Mistakes

  • Querying the container on the container element itself (an element cannot query its own container)
  • Forgetting to set container-type on the parent, so @container queries match the viewport instead
  • Using container queries when a media query is actually more appropriate (global layout vs component layout)
  • Nesting @container without naming, causing ambiguity about which ancestor is being queried

Note

Use container queries for component-level responsiveness (cards, widgets, sidebars) and media queries for page-level layout (header, grid columns, font scale). Combining both gives you full responsive control.

Exercises

Write CSS to style the HTML scaffold. The preview updates live — when it looks right, mark as done.

Loading editor…

Completed: 0 / 3 exercises

Knowledge Check

Question 1 of 4

Which CSS property marks an element as a container for container queries?