Web Development 5-8 minutes

Container Queries and :has(): Modern CSS You Can Use in Production Now

Diego Cortés
Diego Cortés
Full Stack Developer & SEO Specialist
Share:
Container Queries and :has(): Modern CSS You Can Use in Production Now

Container queries became Baseline in February 2023 and the :has() selector in December 2023: by 2026 using them in production is standard practice. Learn to build components that respond to their own container with these two modern CSS features.

From Media Queries to Container Queries

For years, media queries were the only tool for responsive CSS. They work, but they have a structural limitation: they only know the viewport size, not the size of the component you are styling.

The Component That Doesn't Know Its Own Width

Imagine a card used both in the sidebar and in the main content area. In one case it is 300 pixels wide and in the other 800, but media queries cannot tell the two situations apart: both happen at the same viewport size. The result is a pile of workarounds like conditional classes from JavaScript, width calculators, or nested media queries nobody wants to maintain. Container queries solve exactly that problem: the component reacts to the size of its own container.

What a Containment Context Is

For a component to query its container's size, that container must be registered as one. That registration creates what is called a containment context: an element that acts as a size reference for its descendants. Only elements inside that context can use container queries against it, and the browser knows internal size changes must not propagate further, which also improves layout performance.

Container Queries in Practice

The API is straightforward: you declare a container with one CSS property and then write conditional rules with @container. Let's look at the key pieces.

container-type and container-name

To register a container you use the container property, which combines container-type and container-name. The most common value is container-type: inline-size, which creates a context based on the container's width. With container-name you can give it a name and query it explicitly:

/* CSS */
.card-wrapper { container: card / inline-size; }

Then any descendant can react to that container's width:

/* CSS */
@container card (min-width: 600px) {
  .card__media { display: block; }
}

Container Units: cqw, cqh, cqi, and cqb

Besides queries, modern CSS offers units relative to the container, the equivalent of viewport units but with a different context: cqw is 1 percent of the container's width, cqh is 1 percent of its height, cqi is 1 percent of its inline size, and cqb is 1 percent of its block size. There are also cqmin and cqmax, which take the smaller or larger of cqi and cqb. They are ideal for typography and spacing that must scale with the container.

Style Queries: @container style()

Container queries can also query container properties, not just its size. With @container style(...) you apply styles based on a CSS property value of the container, opening the door to theme or state variants without touching classes. It is a newer feature, but it already has real production use cases.

:has(), the Selector That Looks Inside

The :has() selector is the perfect complement to container queries. While the latter respond to the container's size, :has() lets you style an element based on what it contains. It is called the parent selector, because finally a parent can react to its children.

Real-World Cases: Cards with Images and Forms with Errors

A classic case: a card that adjusts its spacing when it includes an image. With :has() you don't need an extra class in the HTML:

/* CSS */
.card:has(.card__media) { padding: 0; }

Another very useful example: a form group that changes its border when the inner field is invalid:

/* CSS */
.field-group:has(input:invalid) { border-color: #dc2626; }

Performance and Best Practices

Modern engines resolve :has() efficiently, but you should avoid overly complex selectors evaluated against many nodes at once. In practice, using it in moderation with simple selectors works fine even on long lists. The golden rule: if a class or attribute solves it, use that; :has() shines when the HTML should not change just for styling.

Browser Support in 2026: From Baseline to Production

The question everyone asks is whether these features can be used today. The short answer is yes, and the support data confirms it.

The Baseline Timeline

Container queries became Baseline newly available in February 2023, and :has() did the same in December 2023. Since then, Chrome, Firefox, Safari, and Edge support them stably. The Baseline project, driven by the web.dev team, classifies web platform features by compatibility, and both have been in the safe-to-use category for years. Polyfills only make sense if a significant part of your audience uses very old browsers, something increasingly rare in 2026.

What Else You Can Use Today: CSS Nesting and Cascade Layers

These two features are not alone: the modern CSS of 2026 also includes native CSS nesting, cascade layers for organizing specificity, the View Transitions API, and the Popover API, among others. Together they completely change how you structure a stylesheet: fewer preprocessors, fewer invented utility classes, and more declarative CSS that the browser understands directly.

Complete Example: A Card That Adapts Itself

Let's close with an example that combines everything. A card that displays horizontally when its container is wide and vertically when it is narrow, and that also adjusts its padding when it has an image:

/* CSS */
.card { container: card / inline-size; }

@container card (min-width: 480px) {
  .card { display: grid; grid-template-columns: 200px 1fr; }
}

.card:has(.card__media) { padding: 0; }
.card__title { font-size: clamp(1rem, 4cqi, 1.5rem); }

The same component, without a single conditional class, changes its layout based on the space it actually has and scales its typography with container units. Drop it in the sidebar or in the main content and it will adapt by itself.

Conclusion

Container queries and :has() are the heart of modern CSS in 2026: components that respond to their own context and selectors that look inside, both with stable support in all major browsers. You don't need to rewrite your entire stylesheet: start with one reusable component, apply a containment context, and let :has() remove unnecessary classes. The result is cleaner, more maintainable, and more predictable CSS. Keep reading the blog for more web development articles.

Categories