03 / 20
All 20 in 20 CSS Container Queries
- 01Container Queries Getting Started
- 02Container Query Units cqi cqw cqmin
- 03Named Containers with container-name
- 04Card Component Adapting to Container Width
- 05Sidebar Aware Main Content Reflow
- 06Container Queries vs Media Queries
- 07CSS Style Queries with container style
- 08Scroll State Container Queries
- 09Fluid Typography with Container Units
- 10Dashboard Widget Component Resizing
- 11Responsive Product Card Grid Reflow
- 12Media Object Layout Inline to Stacked
- 13Dynamic Form Layout Adaptation
- 14Navigation Component Collapse by Container
- 15Responsive Table to Card Layout Switch
- 16Progressive Enhancement and Fallback Strategy
- 17Nested Container Contexts
- 18Avoiding Infinite Layout Loops
- 19Combining Container Queries with CSS Grid
- 20Debugging Container Query Sizing Issues
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.
Build UI like this from scratch: Flexbox, Grid, animations & responsive CSS
ZTM · The CSS Bootcamp · 30‑day money-back guarantee · Affiliate link
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>@container (min-width: 18em)</code></p>
<div class="cq-03__page">
<p class="cq-03__w">outer container · cq-03-page · wide</p>
<div class="cq-03__card">
<p class="cq-03__w cq-03__w--in">inner container · cq-03-card · 16rem</p>
<div class="cq-03__badge cq-03__badge--anon">
<span class="cq-03__no">resolved against the inner container — 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>@container cq-03-page (min-width: 18em)</code></p>
<div class="cq-03__page">
<p class="cq-03__w">outer container · cq-03-page · wide</p>
<div class="cq-03__card">
<p class="cq-03__w cq-03__w--in">inner container · cq-03-card · 16rem</p>
<div class="cq-03__badge cq-03__badge--named">
<span class="cq-03__no">resolved against the inner container — no match</span>
<span class="cq-03__yes">resolved against cq-03-page — 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 — <code>container-name: cq-03-page cq-03-shell</code> answers to either.</p>
</div>
</section><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>@container (min-width: 18em)</code></p>
<div class="cq-03__page">
<p class="cq-03__w">outer container · cq-03-page · wide</p>
<div class="cq-03__card">
<p class="cq-03__w cq-03__w--in">inner container · cq-03-card · 16rem</p>
<div class="cq-03__badge cq-03__badge--anon">
<span class="cq-03__no">resolved against the inner container — 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>@container cq-03-page (min-width: 18em)</code></p>
<div class="cq-03__page">
<p class="cq-03__w">outer container · cq-03-page · wide</p>
<div class="cq-03__card">
<p class="cq-03__w cq-03__w--in">inner container · cq-03-card · 16rem</p>
<div class="cq-03__badge cq-03__badge--named">
<span class="cq-03__no">resolved against the inner container — no match</span>
<span class="cq-03__yes">resolved against cq-03-page — 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 — <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;
}.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;
}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 @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>@container (min-width: 18em)</code></p>
<div class="cq-03__page">
<p class="cq-03__w">outer container · cq-03-page · wide</p>
<div class="cq-03__card">
<p class="cq-03__w cq-03__w--in">inner container · cq-03-card · 16rem</p>
<div class="cq-03__badge cq-03__badge--anon">
<span class="cq-03__no">resolved against the inner container — 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>@container cq-03-page (min-width: 18em)</code></p>
<div class="cq-03__page">
<p class="cq-03__w">outer container · cq-03-page · wide</p>
<div class="cq-03__card">
<p class="cq-03__w cq-03__w--in">inner container · cq-03-card · 16rem</p>
<div class="cq-03__badge cq-03__badge--named">
<span class="cq-03__no">resolved against the inner container — no match</span>
<span class="cq-03__yes">resolved against cq-03-page — 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 — <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;
}
```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 @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>@container (min-width: 18em)</code></p>
<div class="cq-03__page">
<p class="cq-03__w">outer container · cq-03-page · wide</p>
<div class="cq-03__card">
<p class="cq-03__w cq-03__w--in">inner container · cq-03-card · 16rem</p>
<div class="cq-03__badge cq-03__badge--anon">
<span class="cq-03__no">resolved against the inner container — 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>@container cq-03-page (min-width: 18em)</code></p>
<div class="cq-03__page">
<p class="cq-03__w">outer container · cq-03-page · wide</p>
<div class="cq-03__card">
<p class="cq-03__w cq-03__w--in">inner container · cq-03-card · 16rem</p>
<div class="cq-03__badge cq-03__badge--named">
<span class="cq-03__no">resolved against the inner container — no match</span>
<span class="cq-03__yes">resolved against cq-03-page — 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 — <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-pageandcq-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
18emto watch the anonymous query start matching, which is the failure mode in reverse. - Convert the two long-hand declarations to the
containershorthand, or the reverse, to see they are equivalent. - Swap the offset shadow for a hairline border by editing
--shtotransparentif 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
@containerresolves against the nearest ancestor with acontainer-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: cardon one page will cross-resolve; prefix every name. - The
containershorthand resets the half you omit — a barecontainer-type: inline-sizeafter 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
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 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.