Skip to main content

06 - CSS Container Queries: Truly Responsive Components

CSS Container Queries: Componenti Veramente Responsivi Per anni, il responsive design ha significato: "adatta il layout al viewport".

What do you think about this article?

At a Glance

CSS Container Queries: Componenti Veramente Responsivi Per anni, il responsive design ha significato: "adatta il layout al viewport".

CSS Container Queries: Truly Responsive Components

For years, responsive design meant: "adapt the layout to the viewport." A component card with @media (max-width: 768px) he knows how wide it is the screen, but he doesn't know how much space he actually has available on his context. Put that card in a narrow sidebar and it behaves as if it were on mobile, even if the screen is a 27" desktop. Put it in the main content and it behaves like a desktop even if that container is narrower than a smartphone.

Le CSS Container Queries solve this problem at the root: a component can react to the size of the own container, not of the viewport. With superior browser support88% in Baseline 2025 (Chrome 105+, Firefox 110+, Safari 16+), this technique is production ready.

What You Will Learn

  • The fundamental difference between Media Queries and Container Queries
  • How to define a containment context with container-type
  • The syntax @container for queries
  • Container size queries: inline-size, block-size
  • Container style queries: queries based on custom properties
  • Named containers for hierarchical queries
  • How to integrate container queries into Angular, React and Vue

The Problem with Media Queries

Media queries query the characteristics of the viewport: the width of the screen, the orientation, the color scheme. This works when the layout and simple and a component always occupies a predictable width. But in the designs modern systems, the same component is reused in radically different contexts:

  • A product card on the homepage (3 columns on desktop)
  • The same card in the "related products" sidebar (1 narrow column)
  • The same card in a fullscreen modal (2 columns)
  • The same card on the search page (variable based on active filters)

With media queries, you have to know the context of each usage in advance and write case-specific CSS selectors. With container queries, the e autonomous: it adapts itself to its available space.

Define a Container

To use container queries, the first step is to declare which element is the "container" that will be questioned. It is done with property container-type:

/* Crea un container che risponde alla larghezza (inline-size) */
.card-wrapper {
  container-type: inline-size;
}

/* Crea un container che risponde sia a larghezza che altezza */
.card-wrapper {
  container-type: size;
}

/* Dai un nome al container per query gerarchiche */
.card-wrapper {
  container-type: inline-size;
  container-name: card;
}

/* Shorthand */
.card-wrapper {
  container: card / inline-size;
}

Once an item has container-type, all his descendants they can use @container to query its dimensions.

The Syntax @container

The syntax is identical to media queries, but instead of querying the viewport, query the nearest container with a containment context:

.card {
  /* Layout default: verticale, compatto */
  display: grid;
  grid-template-areas:
    "image"
    "content";
  gap: 12px;
}

.card__image {
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 8px 8px 0 0;
}

/* Quando il container e largo almeno 400px: layout orizzontale */
@container (min-width: 400px) {
  .card {
    grid-template-areas: "image content";
    grid-template-columns: 200px 1fr;
  }

  .card__image {
    aspect-ratio: 1;
    border-radius: 8px 0 0 8px;
  }
}

/* Quando il container e largo almeno 600px: layout espanso */
@container (min-width: 600px) {
  .card {
    grid-template-columns: 280px 1fr;
    gap: 24px;
    padding: 24px;
  }

  .card__title {
    font-size: 1.5rem;
  }
}

/* Range syntax (CSS Level 4) - piu leggibile */
@container (200px <= width <= 400px) {
  .card {
    /* stile per range specifico */
  }
}

Named Containers: Hierarchical Queries

When you have nested containers, you can name the containers to query a specific ancestor instead of closest:

<!-- HTML struttura -->
<main class="layout" style="container: layout / inline-size">
  <aside class="sidebar" style="container: sidebar / inline-size">
    <div class="widget">
      <!-- Questo widget puo interrogare sia "sidebar" che "layout" -->
    </div>
  </aside>
</main>
/* Query sul container "sidebar" (il piu vicino) */
@container sidebar (min-width: 300px) {
  .widget { display: flex; }
}

/* Query sul container "layout" (l'antenato nominato) */
@container layout (min-width: 1200px) {
  .widget { max-width: 400px; }
}

Container Style Queries: The Hidden Feature

In addition to size queries, container queries also support style queries: queries based on the values ​​of the container's CSS custom properties. This feature, supported in Chrome 111+ and Safari 17.4+, opens up possibilities completely new in terms of theming and component variants.

/* Definisci una custom property sul container */
.card-wrapper {
  container-type: style;
  /* La variante del componente viene comunicata via custom property */
  --card-variant: featured;
}

/* Il componente si adatta alla variante del container */
@container style(--card-variant: featured) {
  .card {
    border: 2px solid var(--color-accent);
    background: var(--color-accent-subtle);
  }

  .card__badge {
    display: block; /* mostra il badge "In evidenza" */
  }
}

@container style(--card-variant: compact) {
  .card {
    padding: 8px;
    font-size: 0.875rem;
  }

  .card__image {
    display: none; /* nasconde l'immagine in modalita compatta */
  }
}

This pattern allows you to communicate semantic context from the container to the component without additional CSS or JavaScript classes, maintaining encapsulation.

Container measurement units: cqw, cqh, cqi, cqb

With container queries also come new units of measurement relating to the container:

  • cqw: 1% of the width of the container
  • cqh: 1% of the container height
  • cqi: 1% of the container inline size (= cqw for LTR layout)
  • cqb: 1% of the container block size (= cqh)
  • cqmin: the smaller between cqi and cqb
  • cqmax: the larger between cqi and cqb
/* Tipografia fluida relativa al container */
.card__title {
  /* Scala da 16px a 24px in base alla larghezza del container */
  font-size: clamp(1rem, 4cqi, 1.5rem);
}

/* Padding proporzionale al container */
.card {
  padding: 5cqi;
}

/* Gap che si adatta */
.card__grid {
  display: grid;
  gap: clamp(8px, 2cqi, 24px);
}

Container Queries in Angular, React and Vue

Angular: Container-Aware Components

/* card.component.scss */
:host {
  display: block;
  container-type: inline-size;
  container-name: card-host;
}

.card {
  display: grid;
  grid-template-areas: "image" "content";
  gap: 12px;
}

@container card-host (min-width: 400px) {
  .card {
    grid-template-areas: "image content";
    grid-template-columns: 180px 1fr;
  }
}
// card.component.ts
@Component({
  selector: 'app-card',
  templateUrl: './card.component.html',
  styleUrls: ['./card.component.scss'],
  // :host come container - nessun JS necessario per il responsive
  host: { class: 'card-container' }
})
export class CardComponent {
  @Input() product!: Product;
}

React: CSS Modules with Container Queries

/* card.module.css */
.wrapper {
  container-type: inline-size;
  container-name: card;
}

.card {
  display: grid;
  gap: 12px;
}

@container card (min-width: 400px) {
  .card {
    grid-template-columns: 180px 1fr;
  }
}
// Card.tsx
import styles from './card.module.css';

export function Card({ product }: { product: Product }) {
  return (
    <div className={styles.wrapper}>
      <article className={styles.card}>
        <img src={product.image} alt={product.name} />
        <div>
          <h3>{product.name}</h3>
          <p>{product.description}</p>
        </div>
      </article>
    </div>
  );
}

Container Queries vs Media Queries: When to Use What

Scenario Optimal Choice Reason
Global page layout Media Queries The layout depends on the viewport
Reusable components Container Queries The component must adapt to its context
Design system tokens Both Viewports for breakpoints, containers for variants
Dark/light mode Media Queries prefers-color-scheme and a media feature
Dynamic sidebar Container Queries Content fits in open/closed sidebar
Print styling Media Queries @media print is a media query

Pattern Anti: Common Mistakes with Container Queries

Mistake #1: Container Querying Itself

An element with container-type he cannot question himself with @container - it must be a descendant that is modified. Never define a container and a rule @container on the same selector.

Error #2: container-type: size without Height Defined

container-type: size requires the container to have a size defined both in width and height. If you use size on a container without explicit height, queries height e cqh they will not work as expected. USA inline-size in the majority of cases.

Next Steps

You now have truly responsive components thanks to container queries. The next article in the series explores the CSS Anchor Positioning API, which enables to implement tooltips, dropdowns and popovers without a single line of JavaScript: another technique that brings CSS closer to the declarative power that developers have been waiting for for years.

Conclusions

CSS Container Queries fundamentally change the way we build responsive components. Instead of a global breakpoint system that each component must know and respect, each component becomes autonomous and adapts to its own context. This leads to more maintainable code, truly composable design systems and fewer edge cases to manage manually.

With browser support above 88%, container queries are ready for deployment production today. The best way to get started and identify the components of the your design system that are used in multiple contexts - typically card, list item, media object - and progressively convert them to the new paradigm.

Try These Tools

Free developer tools related to this topic.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects