Responsive and modern CSS
Adapt a Brew Notes card to two containers
Reuse the course card in a wide feature slot and a narrow sidebar, then verify layout changes without changing the viewport.
We’ll reuse a Brew Notes feature card in two places on the course page. The wide copy gets a two-column layout; the sidebar copy stays stacked at the same viewport width.
The container queries guide covers syntax, named containers, query units, and containment traps. Here we’ll make the course component work and check the threshold.
Give the card a slot
On a practice copy of your course page, replace one feature card with this markup. The wrapper measures available space, while the article inside changes layout:
<div class="card-slot">
<article class="card">
<h2>Log a brew</h2>
<p>Add a brew in three taps, right after you pour it.</p>
</article>
</div>
Copy this whole wrapper into an aside. For a quick comparison, put the two copies inside these columns:
<div class="card-comparison">
<main>
<!-- Put the first card-slot here -->
</main>
<aside>
<!-- Put the second card-slot here -->
</aside>
</div>
Keep the actual card markup identical. We’ll make its layout depend on the slot.
Add the component rules
Add these rules after the existing card styles in styles.css:
.card-comparison {
display: grid;
grid-template-columns: minmax(0, 1fr) 16rem;
gap: 2rem;
}
.card-slot {
container-name: brew-card;
container-type: inline-size;
}
.card {
display: grid;
gap: 1rem;
overflow-wrap: anywhere;
}
.card h2,
.card p {
margin: 0;
}
.card h2 {
font-size: clamp(1.25rem, 5cqi, 2rem);
}
@container brew-card (min-width: 30rem) {
.card {
grid-template-columns: 10rem minmax(0, 1fr);
align-items: start;
}
}
@media (max-width: 48rem) {
.card-comparison {
grid-template-columns: minmax(0, 1fr);
}
}
The media query keeps the comparison page usable on a small screen. The container query decides how each card uses its own space. At a wide viewport, the main slot can exceed 30rem while the 16rem sidebar stays below it.
The cqi unit sizes the heading against the container’s inline size. clamp() keeps it between 1.25rem and 2rem.
Test the container independently
Keep the browser width fixed. In DevTools, select .card-comparison and temporarily change its second grid track from 16rem to 32rem. Give the viewport enough room for both tracks. The sidebar card should become two-column when its slot reaches 30rem.
Change it back. Confirm the card stacks again. Inspect the wrapper’s content width and the matched @container rule. This proves the component follows its slot instead of the window.
Now test just below and at the threshold. Temporarily give one slot widths of 29rem and 30rem. The first stacks; the second uses two columns. Remove these temporary widths after checking.
Find a containment mistake
Move container-type from .card-slot onto .card and inspect the result. The query cannot use the card itself to style that same card; it looks for an eligible ancestor. Restore the wrapper as the container.
Containment also means children cannot determine the wrapper’s inline size. If adding container-type unexpectedly collapses a wrapper, check that its grid track or parent supplies the width.
Finish with a long heading, a long URL, and 200% zoom. Both copies should stay readable. Keep the page-level media query from the previous lesson and bring the working card-slot markup back into your feature grid.
Lesson completed