Kim BoenderCSS Container Queries: Building Responsive Components That Know Their Own Size
Kim Boender
For years, CSS media queries have been the gold standard for responsive design. We've built entire systems around the assumption that screens have fixed breakpoints: mobile, tablet, desktop. But what happens when your component lives in a 200px sidebar on a desktop screen? Or when the same card component needs to look different in a 600px sidebar versus a 1200px main content area?
Enter CSS container queries—a game-changing feature that lets your components respond to their container's size instead of the viewport. This is how component-driven design should work.
What Are Container Queries?
Container queries allow you to define styles based on the size of a parent container rather than the size of the viewport. Instead of asking "how wide is the browser window?", you're asking "how wide is my parent container?"
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 1fr;
}
}This is a fundamental shift in how we think about responsive design. Your components become truly reusable—they adapt to their environment, not to some preset viewport width.
The Problem With Media Queries
Media queries work great for full-page layouts, but they break down when you're building component libraries. Here's a real scenario:
You design a card component that looks good at 300px on mobile and 500px on desktop. But what if:
- Your design system puts the same card in a 250px sidebar on desktop?
- A product page has a featured section with 2-column cards on wide screens, but your cards were designed for 500px+?
- You need to reuse the same component in different contexts?
With media queries, you'd have to:
- Create multiple versions of the component
- Use wrapper divs with different classes to change behavior
- Make assumptions about where your component will be used
- Update CSS every time the component moves to a new context
Container queries solve this entirely.
Setting Up Container Queries
To use container queries, you need to:
- Define a container context with
container-type - Write container query rules with
@container
Basic Setup
/* Create a container context */
.card-container {
container-type: inline-size;
}
/* Query that container */
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
}The container-type property has two main values:
inline-size: Query the inline (width) dimension. This is what you'll use 99% of the time.size: Query both inline and block dimensions (width and height).
Named Containers
For complex layouts, you can name your containers and target specific ones:
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.main {
container-type: inline-size;
container-name: main-content;
}
/* Only applies in the sidebar container */
@container sidebar (min-width: 300px) {
.card {
padding: 0.5rem;
}
}
/* Only applies in the main content container */
@container main-content (min-width: 600px) {
.card {
padding: 2rem;
}
}The same .card component responds differently depending on which named container it's inside.
Practical Examples
Responsive Card Component
Here's a card that adapts to its container without knowing anything about the page layout:
.card {
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
background: white;
}
@container (min-width: 320px) {
.card {
display: flex;
gap: 1rem;
}
.card-image {
width: 100px;
height: 100px;
flex-shrink: 0;
}
}
@container (min-width: 500px) {
.card {
display: grid;
grid-template-columns: 150px 1fr;
gap: 2rem;
padding: 2rem;
}
.card-image {
width: 150px;
height: 150px;
border-radius: 0.75rem;
}
.card-title {
font-size: 1.5rem;
}
}HTML:
<div class="card-container" style="container-type: inline-size;">
<article class="card">
<img class="card-image" src="image.jpg" alt="Product" />
<div>
<h3 class="card-title">Product Name</h3>
<p class="card-description">Lorem ipsum dolor sit amet...</p>
</div>
</article>
</div>This card works in a 200px sidebar, a 400px column, or a 800px featured section—all without changing the HTML or component structure.
Grid Layouts With Container Queries
.gallery {
container-type: inline-size;
display: grid;
gap: 1rem;
}
@container (max-width: 400px) {
.gallery {
grid-template-columns: 1fr;
}
}
@container (min-width: 400px) and (max-width: 800px) {
.gallery {
grid-template-columns: repeat(2, 1fr);
}
}
@container (min-width: 800px) {
.gallery {
grid-template-columns: repeat(3, 1fr);
}
}
@container (min-width: 1200px) {
.gallery {
grid-template-columns: repeat(4, 1fr);
}
}The gallery adapts based on its actual container width, not the viewport.
Browser Support & Polyfills
Container queries have excellent modern browser support (Chrome 105+, Firefox 110+, Safari 16+), but if you need to support older browsers, there are polyfills available:
<!-- Polyfill for older browsers -->
<script src="https://cdn.jsdelivr.net/gh/GoogleChromeLabs/container-query-polyfill@0.3.1/container-query-polyfill.modern.js"></script>The polyfill provides basic support, though performance isn't quite as good as native implementations.
Advanced Features
Container Query Units
You can use container query units in your CSS values:
cqw: 1% of the container's widthcqh: 1% of the container's heightcqi: 1% of the container's inline sizecqb: 1% of the container's block size
@container (min-width: 400px) {
.card-title {
font-size: max(1rem, 5cqw); /* Scales with container */
}
}Style Queries (Experimental)
The latest spec includes "style queries" (still experimental), which let you query CSS property values:
@container style(--color-scheme: dark) {
.card {
background: #1f2937;
color: #f3f4f6;
}
}This opens up powerful possibilities for context-aware styling.
Container Queries vs Media Queries: When to Use Each
| Aspect | Container Queries | Media Queries |
|---|---|---|
| Use case | Component-level responsive design | Page-level layout breakpoints |
| Context awareness | Adapts to container size | Adapts to viewport size |
| Reusability | Excellent—components work anywhere | Limited—assumes fixed breakpoints |
| Performance | Efficient—only applied to relevant elements | Efficient—single scope |
| Complexity | Better for component libraries | Better for full-page layouts |
| Browser support | Modern browsers only (105+) | All browsers |
Best practice: Use media queries for your main page layout, and container queries for individual components. They're complementary, not competing features.
Real-World Implementation Tips
1. Define Container Boundaries Carefully
/* Good: Define where components can adapt */
.article-grid > article {
container-type: inline-size;
}
/* Avoid: Too many nested containers */
div {
container-type: inline-size;
}2. Test Multiple Container Widths
When developing a component, test it at various widths:
- 250px (sidebar on desktop)
- 350px (mobile viewport)
- 600px (tablet viewport)
- 900px (large desktop)
- 1200px+ (ultra-wide)
3. Combine With Flexible Layouts
Container queries work best with CSS Grid, Flexbox, and CSS Custom Properties:
.card {
--card-padding: clamp(1rem, 10cqw, 2rem);
padding: var(--card-padding);
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: var(--card-padding);
}4. Progressive Enhancement
Use container queries as an enhancement—your components should still be usable without them:
/* Base styles work everywhere */
.card {
padding: 1rem;
background: white;
}
/* Enhanced styles for supporting browsers */
@container (min-width: 400px) {
.card {
padding: 2rem;
display: grid;
}
}Tools & Resources
Open Source Projects
- Container Queries Polyfill - Official polyfill from Google Chrome Labs
- PostCSS Container Queries - PostCSS plugin for transforming container queries
Development Tools
# Check browser support in your CSS
npx browserslist --caniuse-feature=css-container-queries
# Test container queries in DevTools
# Chrome: Open DevTools → Elements → filter CSS by container queriesDebugging Container Queries
Chrome DevTools has excellent support for debugging container queries:
- Open DevTools (F12)
- Go to Elements tab
- Find an element with
container-type - In the Styles panel, you'll see active container queries highlighted
- Hover over
@containerrules to see the container it applies to
Conclusion
CSS container queries represent a fundamental shift in how we approach responsive component design. Instead of fighting against viewport-based media queries, you can now build components that truly understand their environment and adapt intelligently.
Start using container queries today for new components, and gradually migrate existing components as browser support improves. Your component library will be more reusable, maintainable, and flexible than ever before.
The era of "works at 768px but breaks at 750px" is over. Welcome to the future of responsive design.