CSS Container Queries for Card Layouts
Switch a product card from stacked to two columns based on its own inline size with container-type, named containers, and cqw units.
Code
/* Markup contract:
<article class="card-shell"><div class="card">
<img class="card__media" src="/desk.jpg" alt="Standing desk">
<div class="card__body">
<h2 class="card__title">Standing desk</h2>
<p>Height-adjustable frame with a memory preset.</p>
</div>
</div></article> */
.card-shell {
container-type: inline-size;
container-name: card;
}
.card {
display: grid;
gap: var(--space-3, 1rem);
padding: var(--space-4, 1.5rem);
border: 1px solid var(--color-border, #d4d4d8);
border-radius: var(--radius-lg, 0.75rem);
background: var(--color-surface, #ffffff);
}
.card__media {
inline-size: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
border-radius: calc(var(--radius-lg, 0.75rem) - 0.25rem);
}
.card__title {
margin-block: 0;
font-size: 1.15rem;
text-wrap: balance;
}
/* The query measures .card-shell, not the viewport. */
@container card (min-width: 30rem) {
.card {
grid-template-columns: minmax(12rem, 2fr) 3fr;
align-items: start;
}
.card__title {
font-size: clamp(1.15rem, 1rem + 2cqw, 1.6rem);
}
}
@container card (min-width: 48rem) {
.card {
grid-template-columns: minmax(14rem, 1fr) 2fr;
}
}
/* Viewport fallback for browsers without container query support. */
@supports not (container-type: inline-size) {
@media (min-width: 48rem) {
.card {
grid-template-columns: minmax(14rem, 1fr) 2fr;
align-items: start;
}
}
}Report a problem with this exampleOpens a pre-filled issue on GitHub.