Modern CSS: Container Queries & :has()
🧩 What Are Container Queries?
💡 Container queries let components adapt their styles based on the size (or properties) of their parent container, not just the viewport—making truly modular, reusable components possible (dev.to).
How They Work
Declare a container:
.card-wrapper { container-type: inline-size; container-name: card; }
Write queries:
@container card (min-width: 400px) { .card { flex-direction: row; } }
This allows a
card
to switch layout based on available space, regardless of viewport size (joshwcomeau.com).Browser Support
All major browsers—Chrome, Edge, Firefox, Safari—support container queries since 2023, making them production-ready as of 2025 (joshwcomeau.com).
🔧 Quick Example: Responsive Card Component
HTML
CSS
Outcome: a card that adapts whether it's in a sidebar, modal, or grid—without viewport media queries (medium.com).
🚀 Why Container Queries Matter
Component encapsulation: styles stay within components, no global media query pollution (medium.com).
Flexible layouts: perfect for cards, widgets, sidebars—they respond based on context, not just screen size .
Simplified maintenance: fewer magic breakpoints, more predictable design behaviors (en.wikipedia.org).
⚠️ Pitfalls & Best Practices
Common Pitfall | Recommendation |
---|---|
Forgot container-type/name | |
Layout shifts | Fix container dimensions via flex/grid to prevent reflow . |
Polyfill use | Use @supports or JS fallbacks for unsupportive browsers . |
🌟 Introducing :has()
– The New Parent-Selector
What Is It?
The
:has()
pseudo-class targets an element if it contains a matching child or sibling—closing a longstanding gap in CSS selectors (developer.mozilla.org).Browser Support
As of mid-2025, about 93% of browsers support
:has()
, including Chrome 105+, Safari 15.4+, Firefox 121+, and Edge 105+ (caniuse.com).Example Use Cases
Style parent when it has a link or image:
article:has(img) { border-left: 4px solid green; }
Adjust heading spacing when subtitle exists:
.header-group:has(.subtitle) h2 { margin-bottom: 0.2rem; }
Select previous sibling using
+
: h2:has(+ p) { margin-bottom: .25rem; }
🧪 Putting :has()
and Container Queries Together
These features synergize beautifully:
Layout + content-aware styling: e.g.
.card:has(img) { background: #f0f0f0; } @container card (min-width: 500px) { .card:has(img) { flex-direction: row; } }
Form validation & highlight:
form:has(input:invalid) { border: 2px solid red; }
Menu interactions without JS:
header:has(.menu-open) { background: rgba(0,0,0,.8); }
✅ Final Takeaways
Container queries enable responsive, context-aware styling without global breakpoints.
:has()
empowers CSS to react to content and structure. Together, they allow for clean, modular, dynamic styling—less JS, fewer hacks, far more maintainable.
🚀 Next Steps for Developers
Audit your components and identify spots for container queries.
Experiment with
:has()
in cards, forms, and layout wrappers. Use
@supports
to ensure graceful degradation: @supports not (selector(.foo:has(.bar))) { /* fallback styles */ }
Measure & optimize for performance on deeply nested pages.
If you’d like, I can prepare a full codepen demo combining both features or write a comparison of container queries vs media queries with visual examples. Just say the word!