Tailwind CSS v4 Container Queries for Components That Travel
For a decade, responsive design mostly meant viewport media queries. That
works for headers and page grids. It fails for reusable components: the same
card in a wide main column and a narrow sidebar should not both wait for
lg: on the window.
CSS container queries fix that. An element styles itself based on the
size of a parent container. Tailwind CSS v4 brings this into core—no
@tailwindcss/container-queries plugin required.
The two-layer mental model
| Layer | Tool | Question it answers |
|---|---|---|
| Page chrome | sm: md: lg: |
How should the layout shell change with the device? |
| Component guts | @sm: @md: @lg: |
How should this widget change with its slot width? |
Nav collapse, sidebar visibility, and multi-column page grids stay on
viewport variants. Card internals, comment widgets, and pricing tiles move
to container variants so they remain portable.
Minimal pattern
<article class="@container">
<div class="flex flex-col gap-4 @md:flex-row @md:items-center">
<img class="w-full @md:w-40" src="..." alt="" />
<div>
<h3 class="text-lg @md:text-xl">Title</h3>
<p class="text-sm @lg:text-base">Summary…</p>
</div>
</div>
</article>
Mark a parent with @container, then swap md: for @md: on children.
Remember: container breakpoint scales differ from viewport scales
(@md is typically narrower than md). Tune via @theme if your design
tokens demand it.
Nested layouts: name the container
When containers nest, query a specific ancestor:
<div class="@container/main">
<aside class="@container/sidebar">
<div class="@md/sidebar:block @md/main:hidden">…</div>
</aside>
</div>
Gotchas that waste afternoons
- Unsized parents. A flex child without a real width may report 0 for
container queries. Ensure the container establishes inline size. - Hiding the container.
display: noneon the@containeritself
collapses measured width—hide an outer wrapper instead. - Mixing layers carelessly. Do not “fallback”
@md:withmd:on the
same property unless you intentionally want both page and slot rules.
Why this matters for Django + Tailwind sites
Server-rendered partials (and HTMX swaps) drop the same component into
different regions. With container queries, the browser re-resolves styles
when the slot changes—no prop-drilled size="compact" variants, no
Alpine watchers for width.
Ship page structure with classic breakpoints. Teach components to respect
their container. That split is the durable responsive architecture Tailwind
v4 finally makes convenient.