Pure CSSMIT licensed

Named Containers with container-name

An anonymous @container resolves against the nearest ancestor that establishes one, which in a nested component is usually not the one you meant. Naming the ancestor with container-name and querying @container cq-03-page (min-width: 18em) targets it directly. Both panels nest identically, so the wrong answer and the right one sit side by side.

Live Demo
Try it

Build UI like this from scratch: Flexbox, Grid, animations & responsive CSS

ZTM · The CSS Bootcamp · 30‑day money-back guarantee · Affiliate link

10% off at checkout with code
Check ZTM Course

The code

<section class="cq-03" aria-labelledby="cq-03-h">
  <fieldset class="cq-03__theme">
    <legend class="cq-03__themelegend">Theme</legend>
    <input class="cq-03__themeinput" type="radio" name="cq-03-theme" id="cq-03-theme-auto" checked>
    <label class="cq-03__themeopt" for="cq-03-theme-auto">Auto</label>
    <input class="cq-03__themeinput" type="radio" name="cq-03-theme" id="cq-03-theme-light">
    <label class="cq-03__themeopt" for="cq-03-theme-light">Light</label>
    <input class="cq-03__themeinput" type="radio" name="cq-03-theme" id="cq-03-theme-dark">
    <label class="cq-03__themeopt" for="cq-03-theme-dark">Dark</label>
  </fieldset>
  <div class="cq-03__stage">
    <header class="cq-03__head">
      <h2 class="cq-03__h" id="cq-03-h">Which ancestor answers?</h2>
      <p class="cq-03__lede">Identical nesting in both panels. Only the query differs: one is anonymous, one names the outer container.</p>
    </header>

    <div class="cq-03__row">
      <section class="cq-03__panel" aria-label="Anonymous query">
        <p class="cq-03__cap"><b>Anonymous</b> <code>&#64;container (min-width: 18em)</code></p>
        <div class="cq-03__page">
          <p class="cq-03__w">outer container &middot; cq-03-page &middot; wide</p>
          <div class="cq-03__card">
            <p class="cq-03__w cq-03__w--in">inner container &middot; cq-03-card &middot; 16rem</p>
            <div class="cq-03__badge cq-03__badge--anon">
              <span class="cq-03__no">resolved against the inner container &mdash; no match</span>
              <span class="cq-03__yes">matched</span>
            </div>
          </div>
        </div>
      </section>

      <section class="cq-03__panel" aria-label="Named query">
        <p class="cq-03__cap"><b>Named</b> <code>&#64;container cq-03-page (min-width: 18em)</code></p>
        <div class="cq-03__page">
          <p class="cq-03__w">outer container &middot; cq-03-page &middot; wide</p>
          <div class="cq-03__card">
            <p class="cq-03__w cq-03__w--in">inner container &middot; cq-03-card &middot; 16rem</p>
            <div class="cq-03__badge cq-03__badge--named">
              <span class="cq-03__no">resolved against the inner container &mdash; no match</span>
              <span class="cq-03__yes">resolved against cq-03-page &mdash; matched</span>
            </div>
          </div>
        </div>
      </section>
    </div>

    <p class="cq-03__foot">Shorthand: <code>container: cq-03-page / inline-size</code>. A container may hold several names &mdash; <code>container-name: cq-03-page cq-03-shell</code> answers to either.</p>
  </div>
</section>
.cq-03,
.cq-03[data-theme="light"] {
  --bg: #f2e9dd;
  --surf: #fffaf2;
  --surf2: #eadfd0;
  --line: #cbb99f;
  --ink: #241a10;
  --mut: #6d5c48;
  --acc: #c0562b;
  --sh: #241a10;
  --ok: #3f6e3a;
}

.cq-03[data-theme="dark"] {
  --bg: #1a130d;
  --surf: #241a12;
  --surf2: #2f2318;
  --line: #4a3928;
  --ink: #f7ece0;
  --mut: #b8a48c;
  --acc: #f08a56;
  --sh: #000000;
  --ok: #8fc07f;
}

@media (prefers-color-scheme: dark) {
  .cq-03:not([data-theme="light"]) {
    --bg: #1a130d;
    --surf: #241a12;
    --surf2: #2f2318;
    --line: #4a3928;
    --ink: #f7ece0;
    --mut: #b8a48c;
    --acc: #f08a56;
    --sh: #000000;
    --ok: #8fc07f;
  }
}

@supports (color: oklch(0.5 0.1 250)) {
  .cq-03,
    .cq-03[data-theme="light"] {
    --acc: oklch(0.56 0.15 42);
    --ok: oklch(0.5 0.1 142);
  }

  .cq-03[data-theme="dark"] {
    --acc: oklch(0.75 0.14 45);
    --ok: oklch(0.78 0.1 142);
  }

  @media (prefers-color-scheme: dark) {
    .cq-03:not([data-theme="light"]) {
      --acc: oklch(0.75 0.14 45);
      --ok: oklch(0.78 0.1 142);
    }
  }
}

.cq-03 {
  width: 100%;
  min-height: 100vh;
  display: block;
  box-sizing: border-box;
  background: var(--bg);
  color: var(--ink);
  font-family: Rockwell, "Bookman Old Style", "Roboto Slab", Georgia, serif;
  line-height: 1.5;
}

.cq-03 *,
.cq-03 *::before,
.cq-03 *::after {
  box-sizing: border-box;
}

.cq-03__stage {
  max-width: 66rem;
  margin-inline: auto;
  padding: clamp(1rem, 3vw, 2.25rem);
  display: grid;
  gap: 1.25rem;
}

.cq-03__h {
  margin: 0;
  font-size: clamp(1.4rem, 1.1rem + 2vw, 2.1rem);
  font-weight: 400;
  letter-spacing: -0.01em;
}

.cq-03__lede {
  margin: 0.4rem 0 0;
  color: var(--mut);
  font-size: 0.9rem;
  max-width: 56ch;
  font-family: system-ui, sans-serif;
}

.cq-03__row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.cq-03__panel {
  flex: 1 1 26rem;
  min-inline-size: 0;
  display: grid;
  gap: 0.5rem;
  align-content: start;
}

.cq-03__cap {
  margin: 0;
  font-family: system-ui, sans-serif;
  font-size: 0.76rem;
  color: var(--mut);
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: baseline;
}

.cq-03__cap b {
  color: var(--acc);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.7rem;
}

.cq-03__cap code {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.72rem;
}

.cq-03__page {
  container: cq-03-page / inline-size;
  padding: 0.9rem;
  background: var(--surf2);
  border: 2px solid var(--ink);
  border-radius: 2px;
  box-shadow: 6px 6px 0 var(--sh);
}

.cq-03__card {
  container: cq-03-card / inline-size;
  max-inline-size: 16rem;
  margin-top: 0.5rem;
  padding: 0.75rem;
  background: var(--surf);
  border: 2px dashed var(--line);
}

.cq-03__w {
  margin: 0;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.66rem;
  letter-spacing: 0.02em;
  color: var(--mut);
  text-transform: lowercase;
}

.cq-03__w--in {
  color: var(--acc);
}

.cq-03__badge {
  margin-top: 0.6rem;
  padding: 0.65rem 0.7rem;
  min-block-size: 3.25rem;
  display: grid;
  align-content: center;
  background: var(--surf2);
  border-inline-start: 4px solid var(--line);
  font-family: system-ui, sans-serif;
  font-size: 0.78rem;
  color: var(--mut);
}

.cq-03__yes {
  display: none;
}

@container (min-width: 18em) {
  .cq-03__badge--anon {
    background: color-mix(in srgb, var(--ok) 18%, transparent);
    border-inline-start-color: var(--ok);
    color: var(--ink);
  }

  .cq-03__badge--anon .cq-03__no {
    display: none;
  }

  .cq-03__badge--anon .cq-03__yes {
    display: block;
    font-weight: 700;
  }
}

@container cq-03-page (min-width: 18em) {
  .cq-03__badge--named {
    background: color-mix(in srgb, var(--ok) 18%, transparent);
    border-inline-start-color: var(--ok);
    color: var(--ink);
    font-weight: 700;
  }

  .cq-03__badge--named .cq-03__no {
    display: none;
  }

  .cq-03__badge--named .cq-03__yes {
    display: block;
  }
}

.cq-03__foot {
  margin: 0;
  padding-top: 0.85rem;
  border-top: 2px solid var(--ink);
  font-family: system-ui, sans-serif;
  font-size: 0.78rem;
  color: var(--mut);
  max-width: 68ch;
}

.cq-03__foot code {
  font-family: ui-monospace, Menlo, monospace;
  color: var(--ink);
}
/* Theme switch (added 2026-08-25). Pure CSS: three radios + :has(), zero
   JavaScript. Auto inherits both the OS preference and the site's
   [data-theme] stamp; Light and Dark pin the palette and beat both. The
   pinned values are the demo's own [data-theme] declarations reused
   verbatim, so a toggled demo can never drift from how the same demo
   renders under the site theme. */

.cq-03 {
  position: relative;
}

.cq-03__theme {
  position: absolute;
  inset-block-start: 0.875rem;
  inset-inline-end: 0.875rem;
  z-index: 9;
  display: flex;
  align-items: center;
  gap: 0.125rem;
  margin: 0;
  padding: 0.1875rem;
  border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, currentColor 8%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  font-family: system-ui, sans-serif;
}

.cq-03__themelegend {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

.cq-03__themeinput {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

.cq-03__themeopt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 2.25rem;
  min-inline-size: 2.75rem;
  padding: 0 0.6875rem;
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: inherit;
  opacity: 0.55;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

.cq-03__themeopt:hover {
  opacity: 0.85;
}

.cq-03__themeinput:checked + .cq-03__themeopt {
  opacity: 1;
  background: color-mix(in srgb, currentColor 15%, transparent);
}

.cq-03__themeinput:focus-visible + .cq-03__themeopt {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.cq-03:has(#cq-03-theme-light:checked) {
  --bg: #f2e9dd;
  --surf: #fffaf2;
  --surf2: #eadfd0;
  --line: #cbb99f;
  --ink: #241a10;
  --mut: #6d5c48;
  --acc: #c0562b;
  --sh: #241a10;
  --ok: #3f6e3a;
}

.cq-03:has(#cq-03-theme-dark:checked) {
  --bg: #1a130d;
  --surf: #241a12;
  --surf2: #2f2318;
  --line: #4a3928;
  --ink: #f7ece0;
  --mut: #b8a48c;
  --acc: #f08a56;
  --sh: #000000;
  --ok: #8fc07f;
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Container Querie from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Named Containers with container-name
Source: https://codefronts.com/layouts/css-container-queries/named-containers-with-container-name/

An anonymous @container resolves against the nearest ancestor that establishes one, which in a nested component is usually not the one you meant. Naming the ancestor with container-name and querying &#64;container cq-03-page (min-width: 18em) targets it directly. Both panels nest identically, so the wrong answer and the right one sit side by side.
## HTML
```html
<section class="cq-03" aria-labelledby="cq-03-h">
  <fieldset class="cq-03__theme">
    <legend class="cq-03__themelegend">Theme</legend>
    <input class="cq-03__themeinput" type="radio" name="cq-03-theme" id="cq-03-theme-auto" checked>
    <label class="cq-03__themeopt" for="cq-03-theme-auto">Auto</label>
    <input class="cq-03__themeinput" type="radio" name="cq-03-theme" id="cq-03-theme-light">
    <label class="cq-03__themeopt" for="cq-03-theme-light">Light</label>
    <input class="cq-03__themeinput" type="radio" name="cq-03-theme" id="cq-03-theme-dark">
    <label class="cq-03__themeopt" for="cq-03-theme-dark">Dark</label>
  </fieldset>
  <div class="cq-03__stage">
    <header class="cq-03__head">
      <h2 class="cq-03__h" id="cq-03-h">Which ancestor answers?</h2>
      <p class="cq-03__lede">Identical nesting in both panels. Only the query differs: one is anonymous, one names the outer container.</p>
    </header>

    <div class="cq-03__row">
      <section class="cq-03__panel" aria-label="Anonymous query">
        <p class="cq-03__cap"><b>Anonymous</b> <code>&#64;container (min-width: 18em)</code></p>
        <div class="cq-03__page">
          <p class="cq-03__w">outer container &middot; cq-03-page &middot; wide</p>
          <div class="cq-03__card">
            <p class="cq-03__w cq-03__w--in">inner container &middot; cq-03-card &middot; 16rem</p>
            <div class="cq-03__badge cq-03__badge--anon">
              <span class="cq-03__no">resolved against the inner container &mdash; no match</span>
              <span class="cq-03__yes">matched</span>
            </div>
          </div>
        </div>
      </section>

      <section class="cq-03__panel" aria-label="Named query">
        <p class="cq-03__cap"><b>Named</b> <code>&#64;container cq-03-page (min-width: 18em)</code></p>
        <div class="cq-03__page">
          <p class="cq-03__w">outer container &middot; cq-03-page &middot; wide</p>
          <div class="cq-03__card">
            <p class="cq-03__w cq-03__w--in">inner container &middot; cq-03-card &middot; 16rem</p>
            <div class="cq-03__badge cq-03__badge--named">
              <span class="cq-03__no">resolved against the inner container &mdash; no match</span>
              <span class="cq-03__yes">resolved against cq-03-page &mdash; matched</span>
            </div>
          </div>
        </div>
      </section>
    </div>

    <p class="cq-03__foot">Shorthand: <code>container: cq-03-page / inline-size</code>. A container may hold several names &mdash; <code>container-name: cq-03-page cq-03-shell</code> answers to either.</p>
  </div>
</section>
```
## CSS
```css
.cq-03,
.cq-03[data-theme="light"] {
  --bg: #f2e9dd;
  --surf: #fffaf2;
  --surf2: #eadfd0;
  --line: #cbb99f;
  --ink: #241a10;
  --mut: #6d5c48;
  --acc: #c0562b;
  --sh: #241a10;
  --ok: #3f6e3a;
}

.cq-03[data-theme="dark"] {
  --bg: #1a130d;
  --surf: #241a12;
  --surf2: #2f2318;
  --line: #4a3928;
  --ink: #f7ece0;
  --mut: #b8a48c;
  --acc: #f08a56;
  --sh: #000000;
  --ok: #8fc07f;
}

@media (prefers-color-scheme: dark) {
  .cq-03:not([data-theme="light"]) {
    --bg: #1a130d;
    --surf: #241a12;
    --surf2: #2f2318;
    --line: #4a3928;
    --ink: #f7ece0;
    --mut: #b8a48c;
    --acc: #f08a56;
    --sh: #000000;
    --ok: #8fc07f;
  }
}

@supports (color: oklch(0.5 0.1 250)) {
  .cq-03,
    .cq-03[data-theme="light"] {
    --acc: oklch(0.56 0.15 42);
    --ok: oklch(0.5 0.1 142);
  }

  .cq-03[data-theme="dark"] {
    --acc: oklch(0.75 0.14 45);
    --ok: oklch(0.78 0.1 142);
  }

  @media (prefers-color-scheme: dark) {
    .cq-03:not([data-theme="light"]) {
      --acc: oklch(0.75 0.14 45);
      --ok: oklch(0.78 0.1 142);
    }
  }
}

.cq-03 {
  width: 100%;
  min-height: 100vh;
  display: block;
  box-sizing: border-box;
  background: var(--bg);
  color: var(--ink);
  font-family: Rockwell, "Bookman Old Style", "Roboto Slab", Georgia, serif;
  line-height: 1.5;
}

.cq-03 *,
.cq-03 *::before,
.cq-03 *::after {
  box-sizing: border-box;
}

.cq-03__stage {
  max-width: 66rem;
  margin-inline: auto;
  padding: clamp(1rem, 3vw, 2.25rem);
  display: grid;
  gap: 1.25rem;
}

.cq-03__h {
  margin: 0;
  font-size: clamp(1.4rem, 1.1rem + 2vw, 2.1rem);
  font-weight: 400;
  letter-spacing: -0.01em;
}

.cq-03__lede {
  margin: 0.4rem 0 0;
  color: var(--mut);
  font-size: 0.9rem;
  max-width: 56ch;
  font-family: system-ui, sans-serif;
}

.cq-03__row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.cq-03__panel {
  flex: 1 1 26rem;
  min-inline-size: 0;
  display: grid;
  gap: 0.5rem;
  align-content: start;
}

.cq-03__cap {
  margin: 0;
  font-family: system-ui, sans-serif;
  font-size: 0.76rem;
  color: var(--mut);
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: baseline;
}

.cq-03__cap b {
  color: var(--acc);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.7rem;
}

.cq-03__cap code {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.72rem;
}

.cq-03__page {
  container: cq-03-page / inline-size;
  padding: 0.9rem;
  background: var(--surf2);
  border: 2px solid var(--ink);
  border-radius: 2px;
  box-shadow: 6px 6px 0 var(--sh);
}

.cq-03__card {
  container: cq-03-card / inline-size;
  max-inline-size: 16rem;
  margin-top: 0.5rem;
  padding: 0.75rem;
  background: var(--surf);
  border: 2px dashed var(--line);
}

.cq-03__w {
  margin: 0;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.66rem;
  letter-spacing: 0.02em;
  color: var(--mut);
  text-transform: lowercase;
}

.cq-03__w--in {
  color: var(--acc);
}

.cq-03__badge {
  margin-top: 0.6rem;
  padding: 0.65rem 0.7rem;
  min-block-size: 3.25rem;
  display: grid;
  align-content: center;
  background: var(--surf2);
  border-inline-start: 4px solid var(--line);
  font-family: system-ui, sans-serif;
  font-size: 0.78rem;
  color: var(--mut);
}

.cq-03__yes {
  display: none;
}

@container (min-width: 18em) {
  .cq-03__badge--anon {
    background: color-mix(in srgb, var(--ok) 18%, transparent);
    border-inline-start-color: var(--ok);
    color: var(--ink);
  }

  .cq-03__badge--anon .cq-03__no {
    display: none;
  }

  .cq-03__badge--anon .cq-03__yes {
    display: block;
    font-weight: 700;
  }
}

@container cq-03-page (min-width: 18em) {
  .cq-03__badge--named {
    background: color-mix(in srgb, var(--ok) 18%, transparent);
    border-inline-start-color: var(--ok);
    color: var(--ink);
    font-weight: 700;
  }

  .cq-03__badge--named .cq-03__no {
    display: none;
  }

  .cq-03__badge--named .cq-03__yes {
    display: block;
  }
}

.cq-03__foot {
  margin: 0;
  padding-top: 0.85rem;
  border-top: 2px solid var(--ink);
  font-family: system-ui, sans-serif;
  font-size: 0.78rem;
  color: var(--mut);
  max-width: 68ch;
}

.cq-03__foot code {
  font-family: ui-monospace, Menlo, monospace;
  color: var(--ink);
}
/* Theme switch (added 2026-08-25). Pure CSS: three radios + :has(), zero
   JavaScript. Auto inherits both the OS preference and the site's
   [data-theme] stamp; Light and Dark pin the palette and beat both. The
   pinned values are the demo's own [data-theme] declarations reused
   verbatim, so a toggled demo can never drift from how the same demo
   renders under the site theme. */

.cq-03 {
  position: relative;
}

.cq-03__theme {
  position: absolute;
  inset-block-start: 0.875rem;
  inset-inline-end: 0.875rem;
  z-index: 9;
  display: flex;
  align-items: center;
  gap: 0.125rem;
  margin: 0;
  padding: 0.1875rem;
  border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, currentColor 8%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  font-family: system-ui, sans-serif;
}

.cq-03__themelegend {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

.cq-03__themeinput {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

.cq-03__themeopt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 2.25rem;
  min-inline-size: 2.75rem;
  padding: 0 0.6875rem;
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: inherit;
  opacity: 0.55;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

.cq-03__themeopt:hover {
  opacity: 0.85;
}

.cq-03__themeinput:checked + .cq-03__themeopt {
  opacity: 1;
  background: color-mix(in srgb, currentColor 15%, transparent);
}

.cq-03__themeinput:focus-visible + .cq-03__themeopt {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.cq-03:has(#cq-03-theme-light:checked) {
  --bg: #f2e9dd;
  --surf: #fffaf2;
  --surf2: #eadfd0;
  --line: #cbb99f;
  --ink: #241a10;
  --mut: #6d5c48;
  --acc: #c0562b;
  --sh: #241a10;
  --ok: #3f6e3a;
}

.cq-03:has(#cq-03-theme-dark:checked) {
  --bg: #1a130d;
  --surf: #241a12;
  --surf2: #2f2318;
  --line: #4a3928;
  --ink: #f7ece0;
  --mut: #b8a48c;
  --acc: #f08a56;
  --sh: #000000;
  --ok: #8fc07f;
}
```

How this works

An unnamed query asks the nearest container, not the useful one. Both panels below nest a narrow card container inside a wide page container. The left panel's query is anonymous, so it resolves against the inner container — 16rem wide — and never matches, even though the outer container is 40rem:

.page  { container: cq-03-page / inline-size; }   /* 40rem */
.card  { container: cq-03-card / inline-size; }   /* 16rem */

@container (min-width: 18em) { .badge { ... } }              /* asks .card  → no match */
@container cq-03-page (min-width: 18em) { .badge { ... } }   /* asks .page  → matches */

The shorthand is worth using everywhere. container: cq-03-page / inline-size sets container-name and container-type together. Note the order — name first, type after the slash — and note that the shorthand resets whichever half you leave out, so a later container-type alone will clear the name.

A container can carry several names. container-name: cq-03-page cq-03-shell is valid, and any query naming either one matches. That is how a shared shell can answer both a layout query and a component-specific one without a second wrapper element.

The trap: names are resolved, not scoped. Container names live in the document, so two components on the same page using container-name: card can have a named query in one resolve against the other's element. This is why every name in this collection is prefixed cq-NN-. Prefix yours per component or per file — the same discipline you already apply to keyframe names.

Make it yours

  • Change which ancestor answers by moving the name in the query between cq-03-page and cq-03-card — the markup does not change at all.
  • Add a second name to the outer container (container-name: cq-03-page cq-03-shell) and query the alias to confirm both match.
  • Widen the inner container past 18em to watch the anonymous query start matching, which is the failure mode in reverse.
  • Convert the two long-hand declarations to the container shorthand, or the reverse, to see they are equivalent.
  • Swap the offset shadow for a hairline border by editing --sh to transparent if this needs to sit in a flatter design.
  • Retint the whole demo from --acc; the badge fill, the caption rules and the shadow tint all derive from it.

Gotchas — read before shipping

  • An anonymous @container resolves against the nearest ancestor with a container-type, so adding a container anywhere between the query target and the intended ancestor silently changes the answer.
  • Container names are not scoped to a component. Two elements sharing container-name: card on one page will cross-resolve; prefix every name.
  • The container shorthand resets the half you omit — a bare container-type: inline-size after it wipes the name you just set.
  • A query naming a container that does not exist never matches and never warns. Misspell the name and the block simply does nothing.

Browser support

ChromeSafariFirefoxEdge
111+16+113+111+

container-name, the container shorthand and named @container queries shipped in the same release as container queries themselves and have been Baseline since February 2023 (Chrome 105 / Safari 16 / Firefox 110); the Chrome and Firefox numbers above are set by oklch(), used for the coral ramp with an sRGB hex declared first. Below the container-query floor both panels render the identical stacked badge declared before the queries, so the demo reads as one design rather than a broken pair.

Techniques used in this demo

Search CodeFronts

Loading…