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.

CssConfig Management

Code

snippet
/* 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;
    }
  }
}