A Short Introduction to CSS Container Queries

This guide explains how CSS container queries allow components to adapt based on their parent container’s size rather than the viewport, making layouts more flexible and reusable with practical examples.

Image

For years, web devel­op­ers have relied on media queries to make lay­outs respon­sive. But what hap­pens when a com­po­nent needs to adapt based on where it’s placed, rather than the over­all view­port size? That’s exact­ly the prob­lem CSS con­tain­er queries solve.

If you’ve been using media queries and com­po­nent-based design but haven’t yet explored con­tain­er queries, this guide will give you a sol­id foundation.

Why Do We Need Con­tain­er Queries? #

Media queries have been the go-to method for respon­sive design. They allow us to define styles based on the view­port size, which works well for full-page layouts.

For exam­ple, if you want­ed a .card com­po­nent to stack ver­ti­cal­ly on small­er screens, you’d write:

@media (max-width: 600px) {
  .card {
    flex-direction: column;
  }
}

The prob­lem? This approach assumes that screen size is the only fac­tor that mat­ters. But what if that .card appears inside a side­bar? Even if the view­port is large, the side­bar might be nar­row, and the card should still stack.

Media queries don’t help here because they don’t account for the container’s size — only the entire page’s width. This is where con­tain­er queries come in.


How Con­tain­er Queries Work #

Con­tain­er queries let com­po­nents adjust their styles based on their par­ent container’s size, rather than the viewport.

Step 1: Define a Container

To use con­tain­er queries, you first need to declare a con­tain­er. You do this with container-type.

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

This tells the brows­er that .card-container should act as a con­tain­er, and its child ele­ments can respond to its inline size (width).

You can also name a con­tain­er for more spe­cif­ic targeting:

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

The name is option­al but use­ful if you have mul­ti­ple con­tain­er queries in a project.


container-type: size – When to Use It #

By default, container-type: inline-size makes ele­ments respond only to width. But what if you want styles to adapt based on both width and height? That’s where container-type: size comes in.

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

When to Use size Instead of inline-size

  • Wid­gets with fixed width but vari­able height – A chat win­dow, noti­fi­ca­tion box, or cal­en­dar wid­get might need dif­fer­ent styles depend­ing on how tall it is.
  • Square or aspect-ratio-based com­po­nents – If the height changes dynam­i­cal­ly (e.g., an image gallery or inter­ac­tive wid­get), using size ensures the com­po­nent adapts properly.

Note: container-type: size does not enforce lay­out con­tain­ment; it only allows queries to respond to both width and height.

Exam­ple: A Resiz­able Chat Widget
.chat-widget {
  container-type: size;
  width: 300px;
  min-height: 200px;
  max-height: 600px;
  overflow: auto;
  border: 1px solid #ddd;
  padding: 1rem;
}

/* Adjust styles when the chat widget is short */
@container (max-height: 250px) {
  .chat-widget {
    font-size: 14px;
    padding: 0.5rem;
  }
}

This ensures that when the chat wid­get shrinks, the font size and padding adjust accordingly.


Respon­sive Card Lay­out with Con­tain­er Queries #

Let’s put it all togeth­er with a prac­ti­cal example.

HTML

<div class="card-container">
  <div class="card">
    <img src="image.jpg" alt="Example">
    <div class="content">
      <h2>Card Title</h2>
      <p>Card description goes here.</p>
    </div>
  </div>
</div>

CSS

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

.card {
  display: flex;
  gap: 1rem;
}

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

Now, if you drop .card-container into a wide sec­tion, the .card dis­plays in a row. If you place it inside a side­bar, it might shrink below 400px and stack ver­ti­cal­ly—all with­out need­ing a view­port-based media query.


Adap­tive Side­bar Nav­i­ga­tion with Icons #

Let’s take anoth­er exam­ple: a side­bar nav­i­ga­tion that col­laps­es into an icon-only menu when space is limited.

HTML

<nav class="sidebar">
  <ul>
    <li><a href="#"><span class="icon">🏠</span> Home</a></li>
    <li><a href="#"><span class="icon">📄</span> About</a></li>
    <li><a href="#"><span class="icon">📞</span> Contact</a></li>
  </ul>
</nav>

CSS

.sidebar {
  container-type: inline-size;
  width: 250px;
  background: #f4f4f4;
  padding: 1rem;
}

.sidebar ul {
  list-style: none;
  padding: 0;
}

.sidebar li {
  margin-bottom: 1rem;
}

.sidebar a {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  color: black;
}

/* When the sidebar is narrow, hide text and show only icons */
@container (max-width: 150px) {
  .sidebar a span {
    display: none; /* Hide text */
  }
}

When to Use inline-size vs. size #

Prop­er­tyWhat It AffectsUse Case
inline-size (default)Width onlyMost respon­sive com­po­nents (cards, side­bars, grids)
sizeBoth width and heightDynam­ic-height ele­ments (chat win­dows, widgets)

If your com­po­nent only changes in width, stick with inline-size. If you need height-based adjust­ments as well, size is the bet­ter option.


Why You Should Start Using Con­tain­er Queries #

  1. Com­po­nents Become Tru­ly Reusable – A com­po­nent can now adapt to dif­fer­ent lay­outs auto­mat­i­cal­ly, mak­ing it eas­i­er to reuse across a project.
  2. No More Frag­ile Media Queries – Instead of rely­ing on glob­al break­points, styles adjust only when need­ed, reduc­ing main­te­nance headaches.
  3. Bet­ter for Design Sys­tems – Con­tain­er queries allow you to build self-con­tained, flex­i­ble UI com­po­nents that fit into any layout.

Con­tain­er queries are a major step for­ward in respon­sive web design. If you’re already work­ing with CSS media queries, they’re easy to learn — and once you start using them, you won’t want to go back.