Media queries → container queries: the evolution
Media queries ask "how wide is the viewport?". Container queries ask "how wide is my container?". A card in a narrow sidebar should stack vertically; the same card in a full-width area should spread horizontally. Container queries make this possible without JavaScript — the component responds to its own available space, not the browser window.
| concept | media query | container query |
|---|---|---|
| what it asks | "how wide is the @media viewport?" |
"how wide is my @container parent?" |
| breakpoint trigger | browser window resize | container element resize (layout change, sidebar toggle, grid reflow) |
| component reusability | ❌ same component looks same everywhere at same viewport size | ✅ same component adapts to WHERE it's placed |
| Tailwind v4 syntax | md:grid-cols-2 (viewport ≥ 768px) |
@md:grid-cols-2 (container ≥ 288px) |
| setup | nothing — viewport is always available | parent needs class="@container" (sets container-type: inline-size) |
1 · resize the container — watch the card adapt
Drag the slider to change the container width. The card inside uses
@container query variants: at narrow widths it stacks
vertically (1 column); at wider widths it spreads horizontally (2 columns).
This is component-driven responsive design — no viewport resize needed.
left cell
Adapts to container, not viewport.
right cell
Visible when container ≥ @md (288px).
container-type: — · grid-template-columns: —
2 · container breakpoints (Tailwind v4 defaults)
| variant | container min-width | typical use |
|---|---|---|
@sm: | 24rem (384px) | small containers — sidebar widgets |
@md: | 18rem (288px) | default — cards, panels |
@lg: | 32rem (512px) | medium containers — main content |
@xl: | 48rem (768px) | wide containers — full-width sections |
@2xl: | 64rem (1024px) | very wide — dashboards |
@3xl: | 80rem (1280px) | extra wide |
@4xl: | 96rem (1536px) | maximum width |
intent → pattern
| intent | pattern | why |
|---|---|---|
| make a parent queryable | <div class="@container"> |
sets container-type: inline-size — children can use @ variants |
| child responds to container width | @md:grid-cols-2 |
when container ≥ 288px, switch to 2 columns |
| range query (max-width) | @max-md:hidden |
hide when container < 288px (v4 supports @max- variants) |
| named container | class="@container/sidebar" |
child uses @sm/sidebar: to target a specific container |
| override container breakpoints | @theme { --breakpoint-md: 20rem; } |
customize the @md: threshold in your theme |