If you’ve ever built a product grid or card layout with flexbox, you’ve probably run into this frustrating problem: the last row items stick to the left instead of centering when there aren’t enough items to fill the row.
It looks unbalanced. It feels unfinished. And most solutions involve adding extra invisible elements, complex JavaScript, or switching to CSS Grid.
But there’s a simpler pure CSS solution using justify-content: center with calculated margins.
The Problem with Standard Flexbox Grids
When you create a responsive grid with display: flex and flex-wrap: wrap, items naturally align to the left. This works perfectly when every row is full.
But when the last row is incomplete—say you have 7 items in a 3-column grid—those final items align left while empty space sits awkwardly on the right.
For product galleries, team member grids, or portfolio layouts, this looks unpolished.
Why This Matters for Your Store
Visual balance affects user perception. An uncentered last row can make your catalog look incomplete or hastily put together.
This is especially noticeable on:
- Product category pages with varying item counts
- “Related products” sections
- Team or testimonial grids
- Blog post card layouts
The solution needs to be flexible enough to handle any number of items and any number of columns, especially for dynamic content where you don’t control the count.
The Pure CSS Solution
The secret is combining justify-content: center with margins instead of using the gap property. Here’s why it works:
With full rows: There’s no free space left over, so justify-content: center has nothing to center. Items stay aligned edge-to-edge.
With incomplete last rows: There IS free space, so justify-content: center distributes that space evenly, centering the remaining items automatically.
No JavaScript. No media queries for every possible item count. Just clean CSS that adapts automatically.
The Interactive Demo
Try it: Add and remove items, change the column count, and watch how the last row automatically centers.
Code Generator
Use the interactive generator to customize the column count and gap size, then copy the exact CSS and HTML you need for your grid.
How the Pure CSS Method Works
This solution is remarkably simple compared to complex JavaScript calculations.
The Key CSS
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.item {
flex: 0 0 calc(33.33% - 40px);
margin: 20px;
padding: 20px;
box-sizing: border-box;
}
* {
box-sizing: border-box;
}
Why It Works
justify-content: center distributes any leftover space equally on both sides of the content.
Full rows = no leftover space. Items fill the row completely, so justify-content: center does nothing. Items stay edge-aligned.
Incomplete last row = leftover space exists. justify-content: center distributes that space evenly, automatically centering the remaining items.
Margins instead of gap – We use individual margin on each item rather than the gap property. This is because margins are part of the item’s flex calculation, while gap is not. Using margins means each item’s total width (content + margins) is consistent, which makes the centering calculation cleaner.
Padding for internal spacing – The padding: 20px creates space inside each item for your content. Combined with box-sizing: border-box, the padding doesn’t affect the width calculations.
Calculating Item Width
For a 3-column grid with 20px gap:
- Total gap per item = 40px (20px left + 20px right margin)
- Item width =
calc(33.33% - 40px) - Internal padding = 20px (doesn’t affect width due to border-box)
The formula:
flex: 0 0 calc((100% / columns) - (total margin per item))
margin: (gap / 2)
padding: 20px
box-sizing: border-box
For 4 columns with 16px gap:
.item {
flex: 0 0 calc(25% - 32px);
margin: 8px;
padding: 20px;
box-sizing: border-box;
}
Why This is Better Than Other Methods
No JavaScript required – The grid adjusts automatically based on pure CSS. No need to detect last rows or calculate offsets in JavaScript.
No extra markup – You don’t need invisible spacer divs or pseudo-elements.
Works with dynamic content – Add or remove items and centering happens automatically. Perfect for CMS-driven product catalogs.
Simpler than CSS Grid – If you’re already using flexbox, this technique integrates seamlessly without needing to refactor to Grid.
Responsive by default – Just update the flex-basis in media queries to change column count at different breakpoints.
When to Use This Technique
This approach works best when:
✅ You’re using flexbox already (not CSS Grid)
✅ Item count is dynamic (products, blog posts, team members)
✅ You want visual balance without extra markup or JavaScript
✅ Column count might change at different breakpoints
It’s particularly useful for e-commerce product grids where category pages might have 7, 11, or 14 products instead of perfect multiples.
Responsive Breakpoints
To make this work across different screen sizes:
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.item {
/* Mobile: 1 column */
flex: 0 0 calc(100% - 20px);
margin: 10px;
padding: 20px;
box-sizing: border-box;
}
@media (min-width: 640px) {
.item {
/* Tablet: 2 columns */
flex: 0 0 calc(50% - 20px);
}
}
@media (min-width: 1024px) {
.item {
/* Desktop: 3 columns */
flex: 0 0 calc(33.33% - 40px);
margin: 20px;
}
}
Each breakpoint automatically centers incomplete rows without any additional JavaScript.
Applying This to Your Store
To implement this in a product grid:
- Replace
gapwith individualmarginon each item - Add
justify-content: centerto the flex container - Calculate flex-basis using
calc((100% / columns) - (margin * 2)) - Add
paddingfor internal spacing within items - Ensure
box-sizing: border-boxis set globally
For Shopify themes using flexbox product grids, you can usually find the grid CSS in theme.css or within section liquid files. Look for the product grid container and apply these changes.
For WordPress or custom builds, update your grid template’s CSS to use this approach.
Limitations to Know
Margin-based spacing – If you prefer the gap property for other reasons (like better browser dev tools visualization), this technique requires switching to margins.
Uniform item widths required – All items must have the same width. If your grid needs variable-width items, CSS Grid might be a better choice.
Still requires media queries – While the centering is automatic, you’ll still need breakpoints to change column counts responsively.
The Bottom Line
Visual polish comes from details like this. Centered last rows signal care and attention to layout—small things that add up to a more professional storefront.
This pure CSS flexbox technique gives you automatic centering without JavaScript complexity, extra markup, or switching to CSS Grid.
If your product grids, team pages, or card layouts suffer from awkward left-aligned last rows, this CSS solution solves it cleanly:
.container { justify-content: center; }
.item {
margin: (gap/2);
padding: 20px;
box-sizing: border-box;
}
That’s it.



