Pricing Table — Stack to Side-by-Side via Container Query
Build a pricing table that stacks plan cards on narrow hosts and switches to side-by-side comparison when the container reaches 720px using @container (min-width: 720px).
Detailed Explanation
Pricing Tables That Live Anywhere
A pricing table embedded in a marketing landing page might span the full viewport, but the same table inside a pop-up or embedded help center needs to look right at 480px or 800px. Container queries solve this without duplicating markup.
The Markup
<section class="pricing-host">
<div class="pricing">
<article class="plan">…Free…</article>
<article class="plan featured">…Pro…</article>
<article class="plan">…Team…</article>
</div>
</section>
The CSS
.pricing-host {
container-type: inline-size;
container-name: pricing;
}
.pricing {
display: flex;
flex-direction: column;
gap: 1rem;
}
@container pricing (min-width: 720px) {
.pricing {
flex-direction: row;
align-items: stretch;
gap: 1.25rem;
}
.plan {
flex: 1;
}
.plan.featured {
transform: scale(1.04);
z-index: 1;
}
}
Featured Plan Treatment
In stacked mode, the "Pro" plan sits in document order — no special positioning needed. In side-by-side mode, scaling it slightly creates the visual hierarchy users expect from pricing tables ("here's our recommendation").
Why 720px?
Three plans need ~220px each to display title, price, and 5-7 features without truncation. With 1.25rem (20px) gaps, that totals ~700px — round up to 720px for safety.
Ribbon Banners
.plan.featured::before {
content: "Most popular";
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
background: var(--primary);
color: white;
padding: 0.2rem 0.75rem;
border-radius: 999px;
font-size: 0.75rem;
}
The ribbon works in both stacked and side-by-side modes because it's positioned relative to each plan card, not the table.
Use Case
Use this pattern for SaaS pricing pages, plan-comparison tables in marketing sites, and pricing widgets embedded in help centers, signup flows, or in-app upgrade modals.