RWD Responsive Card Grid Template
Learn how to build a card grid that automatically reflows from several columns on desktop down to one column on mobile using CSS Grid.
Why Card Grids Break Without a Plan
A row of product cards, blog previews, or team photos looks great on a wide monitor with four or five columns side by side. Shrink that same browser window down to a phone width and those columns get squeezed until the text wraps awkwardly, images distort, and buttons become impossible to tap. A responsive card grid solves this by letting the number of columns change with the available space, so every card stays wide enough to read comfortably no matter what device is looking at it.
The Core Trick: auto-fit and minmax()
CSS Grid gives you a shortcut that removes most of the guesswork: grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)). Read it in two parts. minmax(220px, 1fr) tells the browser 'each column should never be narrower than 220px, but it can grow to fill any extra space.' repeat(auto-fit, ...) tells the browser 'keep repeating that column definition as many times as will fit in the current row width.' Put together, the browser does the column-counting math for you on every resize: wide screens get many 220px-plus columns, narrow screens get fewer, and a phone-width screen naturally ends up with a single full-width column, all without writing a single media query.
Example: Fluid Card Grid with auto-fit / minmax
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* { box-sizing: border-box; }
body { font-family: Arial, sans-serif; margin: 0; padding: 24px; background: #f4f5f7; }
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 20px;
}
.card {
background: #fff;
border-radius: 8px;
padding: 16px;
box-shadow: 0 1px 3px rgba(0,0,0,0.15);
}
.card img { width: 100%; display: block; border-radius: 6px; margin-bottom: 12px; }
.card h3 { margin: 0 0 8px; }
.card p { margin: 0; color: #555; }
</style>
</head>
<body>
<div class='card-grid'>
<div class='card'><h3>Card One</h3><p>Short description of the first card.</p></div>
<div class='card'><h3>Card Two</h3><p>Short description of the second card.</p></div>
<div class='card'><h3>Card Three</h3><p>Short description of the third card.</p></div>
<div class='card'><h3>Card Four</h3><p>Short description of the fourth card.</p></div>
</div>
</body>
</html>- No breakpoints to maintain: the grid recalculates on every pixel of resize, not just at fixed widths you predicted in advance.
- Works for any device: a folding phone, a tablet in landscape, or a browser window dragged to a strange size all get a sensible column count.
- 1fr as the maximum means leftover space is shared evenly instead of leaving a lopsided gap on the right.
- Combine with gap instead of margins so spacing stays even in every direction without collapsing-margin surprises.
Alternative: Fixed Column Counts with Media Queries
Sometimes a design calls for an exact number of columns at each size rather than whatever fits, for example 'always exactly 4 columns on desktop, 2 on tablet, 1 on phone' so that cards line up with other page elements. In that case, set a fixed grid-template-columns value and change it inside @media rules at the breakpoints your design specifies. This trades the auto-fit approach's total fluidity for precise, designer-approved column counts at known screen widths.
Example: Media-Query Driven Column Counts
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* { box-sizing: border-box; }
body { font-family: Arial, sans-serif; margin: 0; padding: 24px; }
.card-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.card { background: #fff; border: 1px solid #ddd; border-radius: 8px; padding: 16px; }
@media (max-width: 900px) {
.card-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 500px) {
.card-grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class='card-grid'>
<div class='card'>Card 1</div>
<div class='card'>Card 2</div>
<div class='card'>Card 3</div>
<div class='card'>Card 4</div>
</div>
</body>
</html>Whichever technique you choose, test the grid by dragging the browser edge slowly from wide to narrow rather than only checking a phone and a desktop size. This reveals the in-between widths, like a tablet in portrait mode, where a column count that looked fine at the two extremes can suddenly feel cramped.