Flexbox deep dive: flex-wrap, grow, and shrink for the real subscription cards
Part 9 covered a real, simple two-item header. This part covers the Flexbox properties that matter once there are more real items than reliably fit in one row — Bright Leaf Coffee's actual subscription cards, which need to wrap gracefully and size themselves sensibly.
The real problem: three cards, no wrap
.card-row {
display: flex;
gap: var(--space-lg);
}On a wide viewport: all three cards fit comfortably in one row
On a narrow viewport: by Flexbox's real default, the cards shrink
to fit — sometimes past the point of remaining actually readableBy real, default behavior, Flexbox tries to fit every item into a single row, shrinking items as needed rather than wrapping them onto new rows. For three real product cards on a phone-width viewport, that default produces cards squeezed into an uncomfortably narrow width rather than genuinely reflowing.
flex-wrap: the real, direct fix
.card-row {
display: flex;
flex-wrap: wrap;
gap: var(--space-lg);
}
.product-card {
flex: 1 1 280px;
}flex-wrap: wrap allows real items to move onto a new row once they no longer fit at a reasonable size, rather than shrinking indefinitely. Combined with flex: 1 1 280px on each card (covered next), this produces genuinely responsive behavior with zero media query required — three cards per row on a wide screen, naturally reflowing to two, then one, as the viewport narrows.
flex: the real shorthand for grow, shrink, and basis
.product-card {
flex: 1 1 280px;
/* equivalent to: */
flex-grow: 1;
flex-shrink: 1;
flex-basis: 280px;
}flex-basis → the real, starting size before growing or shrinking
flex-grow → whether (and how much, relative to siblings) an item
grows to fill real leftover space
flex-shrink → whether (and how much, relative to siblings) an item
shrinks when there isn't enough real spaceflex-basis: 280px sets each card's real, ideal starting width. flex-grow: 1 lets cards genuinely expand to fill any leftover row space evenly, rather than leaving an awkward real gap after the last card in a row. flex-shrink: 1 allows cards to shrink somewhat if truly needed, but combined with flex-wrap: wrap, wrapping onto a new row happens well before shrinking would make a card uncomfortably narrow.
A real, unequal example: a featured card that grows more
.product-card {
flex: 1 1 280px;
}
.product-card--featured {
flex: 2 1 280px;
}Since flex-grow values are compared relative to siblings, a featured card with flex-grow: 2 claims twice as much of the real leftover row space as a regular card with flex-grow: 1 — genuinely useful for Bright Leaf Coffee's homepage if the Gift Subscription (the most popular real plan) deserves visually larger real estate than the others in the same row.
Setting only width on a flex item instead of using flex-basis (or the flex shorthand). width is a real, valid property, but it's treated as a real suggestion Flexbox can override once flex-grow or flex-shrink are in play — flex-basis is the property Flexbox's own sizing algorithm actually starts its real calculation from, which is why it's the more reliable choice for genuinely controlling a flex item's size.
align-self: overriding alignment for one real item
.card-row {
display: flex;
align-items: flex-start;
}
.product-card--featured {
align-self: stretch;
}While align-items (part 9) sets cross-axis alignment for every item in a container at once, align-self overrides it for one specific real item — useful when, say, every card aligns to the top of the row by default, but one featured card should genuinely stretch to match the row's tallest real card instead.
Next: CSS Grid fundamentals — a real, two-dimensional layout system for Bright Leaf Coffee's actual page-level layout, not just a single row.