{"id":"l-css-2-5","courseId":"css-mastery","lang":"en","kind":"lesson","summary":"Make a session card change its layout based on the width of the slot it sits in, using size container queries, container units and custom-property style queries.","html":"<p>Waypoint uses the same session card in three places: the main schedule grid, a narrow “Up next” sidebar, and a full-width hero for the keynote. A media query can only ask “how wide is the screen?”, and the screen is the same width in all three cases. So the card in the sidebar got the wide layout, squashed into 280px, until someone added a <code dir=\"ltr\">.sidebar .session-card</code> override, then a <code dir=\"ltr\">.hero .session-card</code> override, and so on.</p>\n<p>The card shouldn’t care where it is. It should care how much room it has. Container queries let it ask exactly that.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Make a container, then query it</h2>\n<p>Two steps. First, declare which element is the container, the slot the card sits in:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">slots.css</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.slot</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  container</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: session / inline-size;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>That shorthand sets <code dir=\"ltr\">container-name: session</code> and <code dir=\"ltr\">container-type: inline-size</code>. The type tells the browser you’ll query this element’s inline size (its width in horizontal writing), so it must be able to calculate that width without looking at the content inside.</p>\n<p>Second, write the card’s layout as a query against that container:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">session-card.css</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">block</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">@container</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> session (width >= 400px) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  .session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    grid-template-columns</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">6</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">fr</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    gap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Now the card stacks in the 280px sidebar and switches to two columns in the 640px grid, with no knowledge of either. The name is optional; an unnamed <code dir=\"ltr\">@container (width &gt;= 400px)</code> uses the nearest ancestor with a size container type. Names help when containers nest and you want to skip one.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 250\" role=\"img\" aria-labelledby=\"l-css-2-5-t1\"><defs><marker id=\"arrow-l-css-2-5-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-css-2-5-t1\">A browser window containing a narrow sidebar slot and a wide main slot. The card in the narrow slot is stacked: time above title. The card in the wide slot is side by side: time column next to the title.</title>\n  <rect class=\"d-box\" x=\"10\" y=\"10\" width=\"660\" height=\"230\" rx=\"12\"/>\n  <text class=\"d-label-muted\" x=\"24\" y=\"34\">viewport: same for both</text>\n  <rect class=\"d-box-accent d-dashed\" x=\"24\" y=\"50\" width=\"200\" height=\"176\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"36\" y=\"72\">.slot 280px</text>\n  <rect class=\"d-box-primary\" x=\"40\" y=\"86\" width=\"168\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-label\" x=\"52\" y=\"111\">09:30</text>\n  <rect class=\"d-box-primary\" x=\"40\" y=\"134\" width=\"168\" height=\"76\" rx=\"6\"/>\n  <text class=\"d-label\" x=\"52\" y=\"160\">Title</text>\n  <rect class=\"d-box-accent d-dashed\" x=\"244\" y=\"50\" width=\"412\" height=\"176\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"256\" y=\"72\">.slot 640px</text>\n  <rect class=\"d-box-primary\" x=\"260\" y=\"86\" width=\"96\" height=\"124\" rx=\"6\"/>\n  <text class=\"d-label\" x=\"272\" y=\"111\">09:30</text>\n  <rect class=\"d-box-primary\" x=\"366\" y=\"86\" width=\"274\" height=\"124\" rx=\"6\"/>\n  <text class=\"d-label\" x=\"378\" y=\"111\">Title</text>\n</svg><figcaption>The same card, two slots: the query measures the slot, not the viewport</figcaption></figure>\n<h2 id=\"sec-2\" tabindex=\"-1\">The two rules that trip everyone</h2>\n<p><strong>An element can’t query itself.</strong> The query looks for an <em>ancestor</em> container, so <code dir=\"ltr\">container-type</code> on <code dir=\"ltr\">.session-card</code> plus <code dir=\"ltr\">@container { .session-card { … } }</code> does nothing for the card itself. Put the container on a wrapper.</p>\n<p><strong>Containment changes how the container is sized.</strong> <code dir=\"ltr\">inline-size</code> containment means the container’s width can’t depend on its children; otherwise a query could change the content, which changes the width, which changes the query, forever.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>A container that collapses to zero</span></p>\n<p>Put <code dir=\"ltr\">container-type: inline-size</code> on a shrink-to-fit element (an unsized flex item, an inline-block, a <code dir=\"ltr\">width: fit-content</code> box) and it collapses, because its width used to come from its content and now can’t. Make the container something whose width comes from outside: a block element, a grid cell, or a flex item with <code dir=\"ltr\">flex: 1</code>.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">Container units</h2>\n<p>Inside a container, you get units relative to it: <code dir=\"ltr\">cqi</code> is 1% of the container’s inline size, <code dir=\"ltr\">cqb</code> 1% of its block size, and <code dir=\"ltr\">cqmin</code>/<code dir=\"ltr\">cqmax</code> the smaller or larger of the two. They make a component scale smoothly, not just at breakpoints:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> h3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  font-size</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">clamp</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.75</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> +</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 2</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">cqi</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1.5</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>In the 280px sidebar the title sits near 1rem; in a 640px slot it grows towards 1.5rem. If no ancestor is a size container, container units fall back to the small viewport units, so they never break.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">Style queries for variants</h2>\n<p>Size isn’t the only thing a card might respond to. The keynote card in the hero is a <em>variant</em>, and container style queries let a parent announce that through a custom property:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.hero</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#953800;--shiki-dark:#FFA657\">--variant</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: featured; }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">@container</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> style(--variant: featured) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  .session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    border-inline-start</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">6</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> solid</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> #6d28d9</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>You don’t need <code dir=\"ltr\">container-type</code> for this: every element is a style container by default, so the query checks the nearest ancestor’s computed <code dir=\"ltr\">--variant</code>. Today, style queries work with custom properties only; querying regular properties like <code dir=\"ltr\">style(display: grid)</code> isn’t supported anywhere yet.</p>\n<aside class=\"callout callout-note\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 16v-4\"/><path d=\"M12 8h.01\"/></svg><span><span class=\"callout-kind\">Note</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Support</span></p>\n<p>Size container queries and container units have been Baseline since February 2023. Style queries on custom properties became Baseline newly available in May 2026, when Firefox 151 shipped them (Chrome since 111, Safari since 18). If you support older Firefox versions, treat style-query styling as an enhancement and make sure the default card looks complete without it.</p>\n</aside>\n<h2 id=\"sec-5\" tabindex=\"-1\">Your turn</h2>\n<p>In the exercise, the card uses a media query, so it gets the wrong layout in at least one slot. Turn <code dir=\"ltr\">.slot</code> into a named container, switch the layout to a container query at 400px, and add a style query for the featured variant. The checks change the slot’s width and set <code dir=\"ltr\">--variant</code> on it to watch the card respond. That closes the layout section; next you’ll scale type and spacing fluidly across all those slot sizes.</p>\n","toc":[{"id":"sec-1","text":"Make a container, then query it","level":2},{"id":"sec-2","text":"The two rules that trip everyone","level":2},{"id":"sec-3","text":"Container units","level":2},{"id":"sec-4","text":"Style queries for variants","level":2},{"id":"sec-5","text":"Your turn","level":2}],"takeaways":["<code dir=\"ltr\">container-type: inline-size</code> turns an element into a container, and <code dir=\"ltr\">@container (width &gt;= 400px)</code> styles its descendants based on that element’s width, not the viewport’s.","An element can’t query itself; put <code dir=\"ltr\">container-type</code> on a wrapper and write the query for the elements inside it.","Inline-size containment means the container’s width can’t come from its content, so a container in a shrink-to-fit context collapses unless something gives it a width.","Container units such as <code dir=\"ltr\">cqi</code> (1% of the container’s inline size) let type and spacing scale with the component.","Style queries on custom properties, such as <code dir=\"ltr\">@container style(--variant: featured)</code>, became Baseline in May 2026; size queries have been Baseline since 2023."],"further":[{"title":"Container size and style queries (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Containment/Container_size_and_style_queries"},{"title":"@container (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@container"},{"title":"Container queries (web.dev Learn CSS)","url":"https://web.dev/learn/css/container-queries"}],"quiz":[{"q":"<p>Why does this rule never apply?</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">container-type</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: inline-size; }</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">@container</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (width >= 400px) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  .session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">@container</code> needs a container name to work.","why":"Names are optional. An unnamed query uses the nearest ancestor container."},{"text":"The query should use <code dir=\"ltr\">min-width</code> instead of the range syntax.","why":"Container queries support the range syntax (<code dir=\"ltr\">width &gt;= 400px</code>) in every browser that supports them."},{"text":"<code dir=\"ltr\">inline-size</code> only works on grid containers.","why":"Any element can be a size container, whatever its display type."},{"text":"The card is querying itself, but a container query only styles the container’s descendants.","why":"Correct. The card looks for an ancestor container and finds none. Put <code dir=\"ltr\">container-type</code> on the wrapper (the slot) and style the card from inside the query."}],"answer":3},{"q":"<p>You put <code dir=\"ltr\">container-type: inline-size</code> on a flex item that has no width set, and it collapses to zero width. Why?</p>","options":[{"text":"Inline-size containment stops the element’s width from depending on its content, and a flex item’s width usually comes from its content.","why":"Correct. With containment the item’s content contributes nothing to its size; give it <code dir=\"ltr\">flex: 1</code>, a width, or put the container on an element that is sized by its parent."},{"text":"Container queries don’t work inside flexbox.","why":"They work anywhere; the problem is how the container itself gets its size."},{"text":"The browser hides containers until a query matches.","why":"Containers are rendered normally whether or not any query matches."}],"answer":0},{"q":"<p>A card’s title has <code dir=\"ltr\">font-size: clamp(1rem, 4cqi, 1.5rem)</code>. What does <code dir=\"ltr\">4cqi</code> refer to?</p>","options":[{"text":"4% of the viewport’s width.","why":"That’s <code dir=\"ltr\">4vw</code>. <code dir=\"ltr\">cqi</code> units resolve against the nearest container, not the viewport."},{"text":"4% of the nearest size container’s inline size.","why":"Correct. In a 400px slot, <code dir=\"ltr\">4cqi</code> is 16px; in a 600px slot, 24px (clamped to 1.5rem)."},{"text":"4% of the title’s own width.","why":"An element can’t measure itself this way; container units always look to an ancestor container."},{"text":"4 times the card’s font size.","why":"Multiples of the font size are written <code dir=\"ltr\">4em</code>; <code dir=\"ltr\">cqi</code> has nothing to do with font size."}],"answer":1},{"q":"<p>Which query applies styles when a parent sets <code dir=\"ltr\">--variant: featured</code>?</p>","options":[{"text":"<code dir=\"ltr\">@media (--variant: featured)</code>","why":"Media queries test the device and viewport; they can’t read custom properties."},{"text":"<code dir=\"ltr\">@supports (--variant: featured)</code>","why":"<code dir=\"ltr\">@supports</code> tests whether the browser understands a declaration, not what value an element has."},{"text":"<code dir=\"ltr\">@container style(--variant: featured)</code>","why":"Correct. Style queries test the computed value of a custom property on the nearest container, and every element is a style container by default."}],"answer":2}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<div class=\"slot\">\n  <article class=\"session-card\">\n    <p class=\"time\">09:30</p>\n    <div class=\"body\">\n      <h3>Container Queries in Production</h3>\n      <p>Cards that adapt to the slot they're in, not the screen.</p>\n    </div>\n  </article>\n</div>","css":".slot {\n  width: 500px; /* the checks change this width */\n}\n.session-card {\n  padding: 12px;\n  border: 1px solid #e5e7eb;\n  border-inline-start: 6px solid #cbd5e1;\n  border-radius: 12px;\n}\n.session-card p, .session-card h3 { margin: 0; }\n.time { color: #6b7280; }\n\n@media (width >= 400px) {\n  .session-card {\n    display: grid;\n    grid-template-columns: 6rem 1fr;\n    gap: 1rem;\n  }\n}\n"},"solution":{"html":"<div class=\"slot\">\n  <article class=\"session-card\">\n    <p class=\"time\">09:30</p>\n    <div class=\"body\">\n      <h3>Container Queries in Production</h3>\n      <p>Cards that adapt to the slot they're in, not the screen.</p>\n    </div>\n  </article>\n</div>","css":".slot {\n  width: 500px; /* the checks change this width */\n}\n.session-card {\n  padding: 12px;\n  border: 1px solid #e5e7eb;\n  border-inline-start: 6px solid #cbd5e1;\n  border-radius: 12px;\n}\n.session-card p, .session-card h3 { margin: 0; }\n.time { color: #6b7280; }\n\n.slot {\n  container: session / inline-size;\n}\n\n@container session (width >= 400px) {\n  .session-card {\n    display: grid;\n    grid-template-columns: 6rem 1fr;\n    gap: 1rem;\n  }\n}\n\n@container style(--variant: featured) {\n  .session-card {\n    border-inline-start-color: #6d28d9;\n  }\n}\n"},"checks":[{"id":"named-container","test":"return style('.slot', 'container-type') === 'inline-size' && style('.slot', 'container-name').split(' ').includes('session');"},{"id":"wide-side-by-side","test":"const setW = async (w) => { $('.slot').style.width = w + 'px'; await tick(16); }; const t = () => $('.time').getBoundingClientRect(); const b = () => $('.body').getBoundingClientRect(); const side = () => t().right <= b().left && Math.abs(t().top - b().top) < 1; const stacked = () => b().top >= t().bottom - 0.5; await setW(500); return side();"},{"id":"narrow-stacked","test":"const setW = async (w) => { $('.slot').style.width = w + 'px'; await tick(16); }; const t = () => $('.time').getBoundingClientRect(); const b = () => $('.body').getBoundingClientRect(); const side = () => t().right <= b().left && Math.abs(t().top - b().top) < 1; const stacked = () => b().top >= t().bottom - 0.5; await setW(300); const ok = stacked(); await setW(500); return ok;"},{"id":"threshold","test":"const setW = async (w) => { $('.slot').style.width = w + 'px'; await tick(16); }; const t = () => $('.time').getBoundingClientRect(); const b = () => $('.body').getBoundingClientRect(); const side = () => t().right <= b().left && Math.abs(t().top - b().top) < 1; const stacked = () => b().top >= t().bottom - 0.5; await setW(399); const below = stacked(); await setW(400); const at = side(); await setW(500); return below && at;"},{"id":"featured-variant","test":"const card = $('.session-card'); const before = style(card, 'border-left-color'); $('.slot').style.setProperty('--variant', 'featured'); await tick(16); const after = style(card, 'border-left-color'); $('.slot').style.removeProperty('--variant'); await tick(16); return before === 'rgb(203, 213, 225)' && after === 'rgb(109, 40, 217)';"}],"title":"Let the card measure its slot","prompt":"<p>The card switches to two columns with a <strong>media query</strong>, so it measures the screen instead of its slot. The checks set <code dir=\"ltr\">.slot</code> to widths between 300px and 500px.</p>\n<ol>\n<li>Make <code dir=\"ltr\">.slot</code> a size container named <code dir=\"ltr\">session</code> that tracks its inline size.</li>\n<li>Replace the media query with a container query: when the <code dir=\"ltr\">session</code> container is <strong>400px or wider</strong>, the card becomes the two-column grid; below that, it stays stacked.</li>\n<li>Add a style query: when <code dir=\"ltr\">--variant</code> is <code dir=\"ltr\">featured</code>, the card’s inline-start border becomes <code dir=\"ltr\">#6d28d9</code>.</li>\n</ol>\n","hints":["<code dir=\"ltr\">container: name / type</code> sets both the name and the type in one declaration.","The grid rules can move unchanged into <code dir=\"ltr\">@container session (width &gt;= 400px) { … }</code>.","For the variant: <code dir=\"ltr\">@container style(--variant: featured) { .session-card { border-inline-start-color: #6d28d9; } }</code>."],"explanation":"<p><code dir=\"ltr\">container: session / inline-size</code> makes the slot a named size container, so <code dir=\"ltr\">@container session (width &gt;= 400px)</code> compares <em>the slot’s</em> width with 400px, whatever the viewport is. The card itself can’t be the container, because a query only styles descendants of the container it measures. The style query doesn’t need a container type: every element is a style container, and the card picks up the <code dir=\"ltr\">--variant</code> value from its parent slot. In browsers without style-query support, the card simply keeps its default grey border.</p>\n","checkLabels":{"named-container":"The slot is an inline-size container named session","wide-side-by-side":"At 500px the time sits beside the content","narrow-stacked":"At 300px the card stacks","threshold":"The switch happens exactly at 400px","featured-variant":"–variant: featured turns the border violet"}},"words":670,"readMinutes":3}