Combining Size and Style Container Queries

Size queries answer "how much room does this component have?". Style queries answer "what has the surrounding context asked this component to be?". Real design systems need both at once: a card that uses its side-by-side media layout only when its section asks for the media style and it has room for it; a promotional block that switches to its compact variant in narrow containers unless its theme demands the full treatment. This page shows how to express those combined conditions, how container resolution works when size and style come from the same or different ancestors, and the resolution trap that makes combined queries silently fail. It belongs to Style Queries & Container State in the Mastering Container Queries & Responsive Layouts guide.

Why combine them

A variant chosen by context but applied regardless of space breaks in narrow placements. A marketing team sets --card-layout: media on a section so its cards show images beside text; the same section later appears in a narrow sidebar, and the side-by-side layout squeezes every card's text into a column two words wide. The variant is a request, and requests should be honoured only when they can be.

Conversely, a size-only switch ignores intent. A card that always goes side by side above 30rem cannot be told by its context to stay stacked in a particular section. Combining the two conditions expresses the real rule: "use the media layout when asked and when there is room".

Both conditions must hold Four cases. Media requested and wide: side-by-side layout. Media requested and narrow: stacked, because there is no room. Not requested and wide: stacked, because not asked. Not requested and narrow: stacked. (width > 30rem) and style(--card-layout: media) wide (> 30rem) narrow media requested side by side stacked: no room not requested stacked: not asked stacked Only one of four combinations changes the layout.

The complete implementation

The demo shows two sections with identical cards. Only the second section requests the media layout, and its cards use it only when their container is wide enough.

Live demoA variant that needs both a request and room
Only the second section requests the media layout, and its card uses it only above 30rem. Drag the frame narrower to watch the request be declined. Drag the bottom-right corner to resize the frame in either direction.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Size and style queries together</title>
<style>
  body { font: 15px/1.5 system-ui, sans-serif; margin: 1rem; }

  /* Sections publish a layout request as a custom property. */
  .section--media { --card-layout: media; }

  /* Each card slot is BOTH the size container and the element where the
     inherited --card-layout is visible, so one rule can test both. */
  .card-slot {
    container: card / inline-size;
  }

  .card {
    display: grid;
    gap: 0.75rem;
    padding: 1rem;
    border: 1px solid #cbd5e1;
    border-radius: 12px;
  }
  .card__media { aspect-ratio: 16 / 9; border-radius: 8px; background: #c7d2fe; }

  /* Media layout only when requested AND there is room. */
  @container card (width > 30rem) and style(--card-layout: media) {
    .card { grid-template-columns: 12rem 1fr; align-items: start; }
    .card__media { aspect-ratio: 1; }
  }
</style>
</head>
<body>
  <section class="section">
    <div class="card-slot"><article class="card"><div class="card__media"></div><p>Default section: always stacked.</p></article></div>
  </section>
  <section class="section section--media">
    <div class="card-slot"><article class="card"><div class="card__media"></div><p>Media section: side by side when wide.</p></article></div>
  </section>
</body>
</html>

The card slot is the single container that both conditions are evaluated against. It has size containment from container-type (inside the container shorthand), and it has --card-layout because custom properties inherit from the section into the slot. One element satisfies both requirements, so one @container rule can test both.

The key technique: one rule resolves one container

A single @container rule — however many conditions it combines — finds exactly one container: the nearest ancestor that matches its name (or any container, if unnamed) and, for size conditions, has the needed containment. Every condition in the rule is then evaluated against that element.

One container for both, or nested rules for two Left: the card slot has size containment and inherits the custom property, so one combined rule works. Right: the section is a named container with the property, and the card slot is a separate size container; the conditions need two nested @container rules, one naming each. Where size and style live decides the syntax section { --card-layout: media } .card-slot size container + inherits the property one rule: a and b section: container "section" .card-slot: container "card" @container section style(…) { @container card (width…) } two nested rules

The trap is to name a container that has only one of the two properties. If the combined rule names section, and the section is not a size container, the size condition cannot be evaluated against it and the rule never matches — even though a size container exists one level down. When the size and the style genuinely belong to different ancestors, nest two rules, each naming the container it needs:

.section { container: section / normal; }   /* style queries need no size containment */
.card-slot { container: card / inline-size; }

@container section style(--card-layout: media) {
  @container card (width > 30rem) {
    .card { grid-template-columns: 12rem 1fr; }
  }
}

Nested rules each resolve their own container, and the inner rule's styles apply only when both match. Relying on inheritance, as the main example does, is simpler when possible; nesting is the general solution. Nesting also documents intent: a reader sees immediately that the section provides the request and the card slot provides the space, which is harder to infer from a single combined condition.

Other useful combinations

The and form is the most common, but or and not cover real design rules too.

Override a size switch with a request. @container card (width > 30rem) or style(--card-layout: compact) makes cards compact in narrow containers or wherever a section explicitly asks for compact cards, even in wide containers. Dense listing pages use this to show many small cards in a wide column.

Exclude a context. @container card (width > 30rem) and not style(--card-layout: stacked) applies the wide layout everywhere there is room except sections that insist on stacking — useful for a print-like editorial section that should never go side by side.

Tiered requests. A request can carry more than two values and be combined with different thresholds: style(--density: comfortable) might need 36rem for the roomy variant, while style(--density: compact) fits at 24rem. Each tier is a separate combined rule, and the thresholds document how much space each variant needs.

When several combined rules can match the same element, their order and specificity decide the result exactly as for any other rules, so write them from least to most specific condition and keep each rule's declarations focused on what that condition changes. A component whose base styles hold the default and whose combined rules each override a small set of properties is far easier to reason about than one where several rules each restate the whole layout.

Designing the request tokens

Style-query-driven variants work best with a small, documented vocabulary of request tokens:

  • Name the request, not the result. --card-layout: media says what the context wants; the component decides what that means at each size. Tokens like --card-columns: 2 hard-code a result the component cannot adapt.
  • Use keywords, not free text. Style queries compare computed values exactly, so a CMS that sometimes writes Media and sometimes media produces cards that sometimes match. Constrain the input.
  • Provide a default. Components should look right when no request is set. Querying for the variant and leaving the default unconditional keeps components usable anywhere.
  • Document interactions with size. For each token, state the minimum container width at which it applies, so designers know that requesting a variant in a narrow sidebar will be silently declined.

The token approach and its theming counterpart are covered in Style Queries With Custom Properties. When the variant switch should animate — the card smoothly rearranging as a section changes its request — the transition techniques in Container-Query-Triggered Keyframe Animations apply equally to style-query-triggered changes.

Browser support

Size container queries are supported in Chrome and Edge 105+, Firefox 110+ and Safari 16+. Style queries for custom properties are supported in Chrome and Edge 111+, Firefox 151+ and Safari 18+, and combining them with size conditions in one rule is supported wherever both are. In engines with size queries but no style queries, a combined rule that contains a style() condition is not applied, so the component falls back to its default, stacked layout; see Style Query Fallbacks and Support for ways to provide a class-based alternative.

FAQ

Can one @container rule test both size and style? Yes. Combine them with and, or and not, as in @container card (width > 30rem) and style(--layout: media). Both conditions are evaluated against the same container, so it must be a size container and have the custom property set on it or inherited.

What if the size and the style live on different ancestors? Nest two @container rules, each naming its container. The outer rule can query a section's style and the inner rule a card's size. Each condition is evaluated against the nearest ancestor with the matching name.

Why does my combined query never match? Usually the container used for the style condition is not a size container, or vice versa. A single @container rule resolves one container for all its conditions, so if the nearest named container has no size containment, the size part fails even though the style part would match.

Should I use a style query or a class for a variant? Use a class when the variant is set directly on the component. Use a style query when the value comes from an ancestor, a design token or a CMS setting that the component cannot see as a class, especially when it should combine with size conditions.

Related articles

More pages in the same section.