How to Use CSS Container Queries (Complete Tutorial 2026)
CSS container queries let components respond to their container size, not the viewport. Complete tutorial with syntax, real examples, browser support, and polyfills.
Get more content like this on Telegram!
Daily AI tips, notes & resources β free
Media queries were always a compromise. You'd build a card component, add breakpoints for small, medium, and large screens β and then someone would put that card in a three-column grid on a large screen, and the "large screen" breakpoint would make it look completely wrong because each column is actually narrow.
Container queries fix this. Instead of asking "how wide is the browser window?", you ask "how wide is this component's container?" The component responds to its actual available space, regardless of where it's placed in the layout.
This is one of my favorite CSS additions in years, and it's now safe to use in production.
Basic Syntax
Container queries require two things: declaring a containment context on the parent element, and writing @container rules for the child elements.
/* Step 1: Declare a containment context */
.card-wrapper {
container-type: inline-size;
/* optional: give it a name */
container-name: card;
/* shorthand: */
container: card / inline-size;
}
/* Step 2: Write container queries for children */
.card {
display: flex;
flex-direction: column;
padding: 16px;
}
/* When the card-wrapper is 400px wide or more */
@container card (min-width: 400px) {
.card {
flex-direction: row;
gap: 20px;
}
.card-image {
width: 140px;
flex-shrink: 0;
}
}
container-type: inline-size tells the browser to track this element's inline (horizontal) size for container queries. Using block-size tracks vertical size (useful but less common). Using size tracks both.
Container Types Explained
/* inline-size: responds to width (horizontal) */
.sidebar { container-type: inline-size; }
/* size: responds to both width and height */
.modal-content { container-type: size; }
/* normal: creates a named container but no size queries */
/* useful for style queries (coming next) */
.theme-region { container-type: normal; container-name: theme; }
For most use cases, inline-size is what you want. size requires the element to have a defined height, which limits its usefulness.
Real Component Example: The Responsive Card
Let's build a card that works beautifully whether it's in a full-width hero, a 3-column grid, or a narrow sidebar.
<div class="card-container">
<article class="card">
<div class="card-image-wrap">
<img src="/post-thumbnail.jpg" alt="Article thumbnail" class="card-image">
</div>
<div class="card-body">
<span class="card-category">Frontend</span>
<h2 class="card-title">Understanding React Server Components</h2>
<p class="card-excerpt">Server components change how we think about data fetching and rendering boundaries in modern applications.</p>
<div class="card-footer">
<span class="card-author">Sarah Chen</span>
<a href="/post/react-server-components" class="card-link">Read more</a>
</div>
</div>
</article>
</div>
/* The containment context */
.card-container {
container-type: inline-size;
container-name: post-card;
}
/* Default (narrow) layout β stacked vertically */
.card {
border-radius: 12px;
overflow: hidden;
border: 1px solid #e2e8f0;
background: white;
}
.card-image-wrap {
aspect-ratio: 16/9;
overflow: hidden;
}
.card-image {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.card:hover .card-image { transform: scale(1.05); }
.card-body {
padding: 16px;
display: flex;
flex-direction: column;
gap: 8px;
}
.card-category {
font-size: 0.75rem;
font-weight: 600;
color: #3b82f6;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.card-title {
font-size: 1.1rem;
font-weight: 700;
line-height: 1.3;
color: #0f172a;
}
.card-excerpt {
font-size: 0.9rem;
color: #64748b;
line-height: 1.6;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 8px;
}
.card-link {
font-size: 0.875rem;
color: #3b82f6;
font-weight: 500;
text-decoration: none;
}
/* Medium container: side-by-side layout */
@container post-card (min-width: 360px) {
.card {
display: flex;
flex-direction: row;
align-items: stretch;
}
.card-image-wrap {
width: 160px;
flex-shrink: 0;
aspect-ratio: unset;
}
.card-body {
padding: 20px;
flex: 1;
}
.card-title { font-size: 1.2rem; }
.card-excerpt { -webkit-line-clamp: 4; }
}
/* Large container: more breathing room */
@container post-card (min-width: 600px) {
.card-image-wrap { width: 220px; }
.card-body { padding: 28px; }
.card-title { font-size: 1.4rem; }
.card-excerpt { -webkit-line-clamp: unset; }
}
This card is now layout-aware. Drop it into a two-column grid, a sidebar, or a full-width section β it adapts automatically without any changes to the component or additional CSS rules.
Container Queries vs Media Queries
| Dimension | Container Queries | Media Queries |
|---|---|---|
| Responds to | Container element size | Viewport (browser window) |
| Use case | Component-level responsiveness | Page-level layout changes |
| Reusability | High (component is self-contained) | Low (component depends on page context) |
| DOM dependency | Requires containment context on parent | None β global |
| Style queries | Yes (CSS variables, properties) | Limited |
| Browser support | ~93% | ~100% |
| Debugging | Slightly more complex | Simple |
The key insight: container queries make components truly reusable. A card component shouldn't need to know if it's in a sidebar or a hero section. With container queries, it doesn't.
Named Containers and Nested Contexts
You can have multiple named containers for different parts of your UI:
.sidebar { container: sidebar / inline-size; }
.main-content { container: main / inline-size; }
.modal { container: modal / size; }
And query them specifically:
/* Only applies when inside the sidebar container */
@container sidebar (max-width: 280px) {
.widget { padding: 12px; }
}
/* Only applies when inside the main container */
@container main (min-width: 500px) {
.widget { display: grid; grid-template-columns: 1fr 1fr; }
}
This precision is useful in complex layouts where the same component appears in multiple contexts with different constraints.
CSS Style Queries (New in 2025)
Style queries are the newer addition to the container query spec β they let you query CSS custom property values, not just sizes.
.product-card-wrapper {
container-type: normal;
container-name: product;
}
/* Style query: if the --featured variable is set to 'true' */
@container product style(--featured: true) {
.product-card {
border: 2px solid #f59e0b;
background: #fffbeb;
}
.product-badge {
display: block;
}
}
<div class="product-card-wrapper" style="--featured: true">
<div class="product-card">
<span class="product-badge">Featured</span>
<!-- ... -->
</div>
</div>
Style queries let you pass state through CSS variables without JavaScript or modifier classes. Browser support for style queries is newer (~85%) but growing fast.
Real-World Patterns
Pattern 1: Navigation That Adapts to Its Container
.nav-container {
container-type: inline-size;
container-name: nav;
}
.nav-list {
display: flex;
gap: 8px;
}
/* Narrow container: icon-only buttons */
@container nav (max-width: 280px) {
.nav-label { display: none; }
.nav-icon { margin: 0; }
}
/* Medium container: icons with labels */
@container nav (min-width: 280px) and (max-width: 500px) {
.nav-label { font-size: 0.75rem; }
}
Pattern 2: Data Table That Stacks on Small Containers
.table-wrapper {
container-type: inline-size;
}
/* Normal table on wide containers */
@container (min-width: 600px) {
.responsive-table { display: table; }
.responsive-table thead { display: table-header-group; }
.responsive-table tr { display: table-row; }
.responsive-table td { display: table-cell; }
}
/* Stacked card layout on narrow containers */
@container (max-width: 599px) {
.responsive-table,
.responsive-table thead,
.responsive-table tbody,
.responsive-table tr { display: block; }
.responsive-table thead { display: none; }
.responsive-table td {
display: flex;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid #e2e8f0;
}
.responsive-table td::before {
content: attr(data-label);
font-weight: 600;
color: #374151;
}
}
For layout context on using these patterns with Grid, see the CSS Flexbox and Grid notes.
Browser Support and Polyfills
| Feature | Chrome | Firefox | Safari | Edge | Global |
|---|---|---|---|---|---|
| Container size queries | 105+ | 110+ | 16+ | 105+ | 93.1% |
| Container style queries | 111+ | 129+ | 17.2+ | 111+ | ~85% |
| Named containers | 105+ | 110+ | 16+ | 105+ | 93.1% |
For the 7% of users on older browsers, the @oddbird/container-queries-polyfill is the most-used option:
<!-- Polyfill via CDN (lightweight, ResizeObserver-based) -->
<script>
if (!('container' in document.documentElement.style)) {
import('https://cdn.jsdelivr.net/npm/@oddbird/css-unpoly/index.js');
}
</script>
The polyfill uses ResizeObserver and PostCSS to replicate container query behavior. It has some limitations (no style queries, slight performance overhead) but covers the size query use case well.
The MDN container queries reference is the authoritative source for syntax details.
Integrating With Tailwind
Tailwind CSS v3.3+ and v4 support container queries via @tailwindcss/container-queries plugin (v3) or natively (v4):
<!-- Tailwind v4 β native container query support -->
<div class="@container">
<div class="flex flex-col @[360px]:flex-row gap-4">
<img class="@[360px]:w-40" src="/thumbnail.jpg" alt="">
<div>
<h2 class="text-lg @[600px]:text-xl">Article Title</h2>
<p class="text-gray-600">Excerpt...</p>
</div>
</div>
</div>
The @container class sets the containment context. The @[360px]:flex-row syntax applies flex-direction: row when the container is 360px or wider. Clean and readable.
The Tailwind CSS cheatsheet has more on container query utilities in Tailwind v4.
Conclusion
Container queries are one of the most impactful CSS additions in recent years. They don't replace media queries β they complement them. Media queries handle page-level layout; container queries make individual components responsive to where they're placed.
If you're building component-based UIs (React, Vue, Angular, Web Components), container queries will improve your code. Components stop depending on the page context and start managing their own responsiveness. That's a meaningful improvement in maintainability.
Start with container-type: inline-size on a component wrapper, write a couple of @container rules, and see how it feels. You'll likely never want to go back to the media query workaround approach.
FAQs
Can I use container queries with CSS Grid? Yes, and it's one of the most useful combinations. Define a grid layout at the container level, then use container queries inside each grid item to adjust how that item displays based on how much space the grid allocated to it.
What's the difference between container queries and media queries? Media queries respond to the viewport (browser window) size. Container queries respond to the size of a specific parent element. A component using container queries will look different in a narrow sidebar versus the same narrow viewport β they're not the same thing.
Do I need a polyfill for container queries in 2026? For most production projects, no. Container queries have 93%+ global browser support. If you need IE11 or very old Chrome/Firefox support, the @oddbird/css-unpoly polyfill works, but for modern browser targets you can use container queries natively.
Frequently Asked Questions
AiTechWorlds Team
β Verified WriterThe AiTechWorlds team is passionate about AI, technology, and education. We create high-quality, research-backed content to help you learn, grow, and succeed in the modern digital world.
Related Articles
CSS Grid vs Flexbox: When to Use Which (With Cheatsheet)
CSS Grid or Flexbox? This guide breaks down when to use each layout method, with code examples, a decision table, and combined patterns.
How to Build a Dark Mode Toggle With CSS and JavaScript
Build a dark mode toggle with CSS variables, localStorage persistence, and prefers-color-scheme support. Full code, accessibility tips, and framework comparison included.
Build a Responsive Navbar With Pure CSS (No JavaScript)
Build a fully responsive hamburger navbar using only HTML and CSS β covering both the checkbox hack and the modern CSS :has() approach with accessibility notes.
10 UI Design Principles Every Web Developer Should Know
Master the 10 core UI design principles that transform average interfaces into intuitive, polished experiencesβwith CSS code examples for each.