Build a flexible layout first, then add breakpoints where the content needs them. Media queries respond to the viewport. Container queries respond to a component’s containing context, which lets the same component adapt differently in a sidebar and in the main content area.

A grid that adapts without a breakpoint

Cards fit the available widthLink

HTML and CSS

HTML

<div class="cards">
  <article>First card</article>
  <article>Second card</article>
  <article>Third card</article>
</div>

CSS

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  gap: 1rem;
}
/* Optional presentation */
.cards > article {
  padding: 1rem;
  background: #dbeafe;
}

Edit HTML or CSS to update the preview as you type. Copy code snippet copies the selected tab. Preview spacing and font defaults are not included.

auto-fit chooses how many columns fit. minmax() sets a preferred minimum and allows each track to grow. min(100%, 12rem) keeps the minimum from exceeding a very narrow container. Copy the document and resize the browser to see the columns change.

Use a media query for page layout

.page { display: grid; gap: 1.5rem; }
@media (min-width: 50rem) {
  .page { grid-template-columns: minmax(0, 1fr) 16rem; }
}

The base layout is one column. At 50rem of viewport width, the page gets a main column and a sidebar. This value belongs to the layout’s needs, not a particular phone model. Use min-width and max-width deliberately, and inspect overflow from long content.

A component-level container query

A card follows its containerLink

HTML and CSS

HTML

<div class="wrapper">
  <article class="card">
    <div class="symbol" aria-hidden="true">CSS</div>
    <div>
      <h2>A reusable card</h2>
      <p>This content changes layout when its wrapper is wide enough.</p>
    </div>
  </article>
</div>

CSS

.wrapper {
  container-type: inline-size;
}
.card {
  display: grid;
  gap: 1rem;
}
@container (min-width: 24rem) {
  .card {
    grid-template-columns: 6rem minmax(0, 1fr);
    align-items: center;
  }
}
/* Optional presentation */
.wrapper {
  max-width: 36rem;
  resize: horizontal;
  overflow: auto;
  border: 1px solid #64748b;
  padding: 1rem;
}
.symbol {
  background: #dbeafe;
  padding: 1rem;
}

Edit HTML or CSS to update the preview as you type. Copy code snippet copies the selected tab. Preview spacing and font defaults are not included.

Drag the wrapper’s resize handle in a supporting desktop browser, or copy the document and change its max-width. Below 24rem, the card stacks; above it, the symbol sits beside the text. The wrapper establishes an inline-size query container. The card is its descendant.

What can go wrong

A query needs an eligible ancestor container. A component cannot size-query itself to change its own layout: put the container on a wrapper. container-type: inline-size introduces containment, which can change how intrinsic sizing is determined; inspect components that previously depended on their content to size their parent.

Container queries do not replace media queries for page-level concerns or user preferences. Add a plain usable layout outside the query so an unsupported query leaves the content readable.

Check the complete interface

Test a narrow viewport, 200% zoom, long words, translated labels, and keyboard focus. Keep images from exceeding their container, and keep code overflow inside its code block. Avoid a fixed page width that requires horizontal scrolling.

For typography, a bound such as max-width: 65ch can keep long text readable. The ch unit is based on the width of the font’s zero glyph, so it is a guide rather than an exact character count.

Sources

MDN: container queries and MDN: responsive design explain setup, containment, and browser compatibility.