skip to content

In native CSS, can an @media block be written inside a style rule, and what do the declarations inside it apply to?

level: middleimportance: should knowfreq 38%

answer

  1. nesting works in both directions
  2. declarations wrap in an implicit &
  3. conditional group rules only
  4. @media adds no specificity
  5. viewport, not the element's own width

basics

~20 s

Yes. Conditional at-rules such as @media, @supports, and @container may be nested inside a style rule, and their declarations apply to that rule's own elements when the condition matches, as if wrapped in a nested & { ... } block.

solid answer

~50 s

Nesting works in both directions. Historically you could only put style rules inside `@media`, which meant repeating the selector in a separate block far from the base rule. With native nesting, a conditional group rule — `@media`, `@supports`, `@container` — can appear directly inside a style rule, and the declarations in it apply to the enclosing rule's subject when the condition holds. `.card { padding: 1rem; @media (width >= 40em) { padding: 2rem; } }` is equivalent to `.card { padding: 1rem; } @media (width >= 40em) { .card { padding: 2rem; } }`. Conceptually the bare declarations are wrapped in an implicit `& { … }`. You can also put full nested rules inside the nested at-rule, and nest at-rules within each other, which is how a component's responsive behaviour ends up in one block instead of scattered across breakpoint sections.

code

css · 15 lines
css
.card {
  padding: 1rem;
  display: block;

  @media (width >= 40em) {
    padding: 2rem;
    display: grid;

    & .title { grid-column: 1 / -1; }
  }

  @supports (display: grid) {
    gap: 1rem;
  }
}

go deeper

for a junior

Know that you can put a @media block inside a rule now, and that the declarations inside it style that same element when the query matches — no need to repeat the selector.

for a middle

Explain the desugaring: bare declarations in a nested at-rule behave as if wrapped in & { … }, and nested conditions combine so every enclosing query must match.

for a senior

Show that you reason about order and cascade — the conditional value must come after the default to win — and that you pick @container over @media when the component, not the viewport, is what varies.

for a principal

Own the convention question: co-locating breakpoints removes the single breakpoint section a team could scan, so decide how query text is kept consistent across a large codebase and how that interacts with container queries.

## The old shape Before nesting, `@media` was strictly an outer wrapper. A component's responsive behaviour had to be written as a second rule inside a media block, repeating the selector: ```css .card { padding: 1rem; } @media (width >= 40em) { .card { padding: 2rem; } } ``` In large sheets those blocks drift far from the base rule, and the selector is duplicated at every breakpoint. ## Nesting at-rules inside style rules CSS Nesting allows conditional group rules to appear inside a style rule: ```css .card { padding: 1rem; @media (width >= 40em) { padding: 2rem; } } ``` The declarations inside the nested `@media` apply to whatever the enclosing rule matches — `.card` itself, not its descendants — whenever the query evaluates true. The mental desugaring is that bare declarations inside a nested at-rule behave as though wrapped in `& { … }`: ```css .card { padding: 1rem; @media (width >= 40em) { & { padding: 2rem; } } } ``` Writing the `& { … }` explicitly is always safe and was required by some early implementations, so you will see it in older examples. ## Which at-rules The ones that make sense inside a style rule are the **conditional group rules**: - `@media` — viewport, media type, and feature queries, including the range syntax `(width >= 40em)`. - `@supports` — feature detection, e.g. `@supports (display: grid) { … }`. - `@container` — container queries, which evaluate against a named or nearest query container rather than the viewport. At-rules that define something rather than conditionally apply declarations — `@font-face`, `@keyframes`, `@import`, `@property` — are top-level constructs and do not belong inside a style rule. ## Style rules inside the nested at-rule A nested at-rule can contain full nested rules as well as bare declarations, and the two compose: ```css .card { display: block; @media (width >= 40em) { display: grid; & .title { grid-column: 1 / -1; } } } ``` At-rules can also nest inside one another, which is how you express "wide viewport *and* the feature is supported": ```css .gallery { @supports (display: grid) { @media (width >= 60em) { grid-template-columns: repeat(3, 1fr); } } } ``` Each layer of conditions must hold for the innermost declarations to apply — the conditions are effectively ANDed together. ## Specificity and the cascade are unaffected A nested `@media` changes *whether* a declaration applies, never how strongly it competes. `@media` contributes nothing to specificity, so within the same cascade layer and origin, the nested declaration wins over the base one for the ordinary reason: same selector, same specificity, later source order. That is why the nested override reads naturally — put the conditional value after the default and it takes over when the query matches. A consequence worth knowing: if you write the media block *before* the base declaration in the same rule, and both target the same property, the base declaration wins even when the query matches, because it comes later. Order matters exactly as it does between two top-level rules. ## Why it is worth using Keeping breakpoints next to the property they modify makes a component readable in one place and makes deletion safe — removing the component removes its responsive rules with it. The cost is that a stylesheet no longer has a single "breakpoints" section to scan, so a house convention (always the same query text, ideally via a custom media convention or a shared constant in the build) matters more. ## Watch the query, not the nesting One genuine gotcha: a nested `@media` still measures the **viewport**, not the element. If a component should react to the space it is given rather than the window, `@container` is the at-rule you want — nesting it inside the component rule looks almost identical but resolves against a query container instead. Container queries are recent, so check support before relying on them.

  • Does a nested `@media` block make its declarations more specific than the rule's own declarations?
    No. At-rules contribute nothing to specificity; they only gate whether the declarations apply. Inside one rule, the conditional value wins because it appears later in source order at equal specificity — so if you write the media block above the default declaration, the default wins even when the query matches.
  • Which at-rules should not be nested inside a style rule?
    Definitional ones. `@font-face`, `@keyframes`, `@property` and `@import` declare resources or names for the whole stylesheet and belong at the top level — `@import` in particular must come before any style rules. The at-rules that nest usefully are the conditional group rules: `@media`, `@supports`, and `@container`.
  • When would you nest `@container` instead of `@media` inside a component rule?
    When the component's layout should depend on the space it is actually given rather than the window size — a card that appears in both a narrow sidebar and a wide main column. `@container` resolves against the nearest matching query container, which requires an ancestor to declare `container-type`. It is a recent feature, so confirm support for your baseline.

saying these in an interview costs you the question

  • Thinking @media can only wrap rules, never be nested
  • Expecting nested @media declarations to hit descendants
  • Assuming a nested at-rule raises specificity
  • Nesting @keyframes or @font-face inside a rule
  • Treating a nested @media as an element-width query

context