
Table of contents
Introduction#
Welcome to Part 3 of the CSS Grid Fundamentals Series — the final and most impactful part!
So far, we’ve explored:
- Part 1: Grid basics, tracks, and layout structure
- Part 2: Grid areas, alignment, spanning, and implicit/explicit tracks
Now, we shift gears to what makes CSS Grid truly shine — responsiveness.
In this post, you’ll learn how to:
- Use fractional units (
fr
) for flexible sizing - Combine
minmax()
withauto-fit
andauto-fill
to create fluid, wrapping grids - Write responsive layouts with or without media queries
- Enhance responsiveness further using container queries
Think of this as your guide to building adaptable, scalable layouts that behave beautifully on any screen — from a small phone to a wide desktop.
Whether you’re designing cards, product grids, or UI dashboards, these tools let you ditch rigid breakpoints and build with confidence.
Fractional Units (fr
)#
The fr
unit stands for fraction of available space. It’s a powerful tool for creating fluid, responsive layouts.
1
2
3
4
5
.grid {
display: grid;
grid-template-columns: 2fr 1fr; /* First column takes 2/3, second takes 1/3 */
gap: 1rem;
}
In this layout:
- The grid container’s space is divided into 3 fractions.
- The first column gets 2 parts, the second column gets 1 part.
Repeating Equal Columns#
You can create equal-width columns easily with repeat()
and 1fr
:
1
2
3
4
5
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr); /* Three equal columns */
gap: 1rem;
}
This setup creates 3 columns of equal width, with a 1rem
gap between both columns and rows. It’s clean and scalable.
minmax()
Function#
minmax(min, max)
is a CSS Grid function that defines a track (row or column) with:
- A minimum size it can shrink to
- A maximum size it can grow to
It’s especially useful when building responsive layouts, because it allows a column or row to be flexible—but within limits.
Syntax:
minmax(<min>, <max>)
-
<min>
– the smallest the track can be (can be 0, 100px, min-content, etc.) -
<max>
– the largest the track can be (can be 1fr, auto, max-content, etc.)
Real-World Use Case: Responsive Cards#
1
2
3
4
5
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
}
1
2
3
4
5
6
<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>
In this example, cards are laid out in rows on large screens and they stack neatly without overflow on small screens.
auto-fit
vs auto-fill
#
Want a grid that adapts to screen width without media queries? Use auto-fit
or auto-fill
along with minmax()
:
1
2
3
4
5
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
What’s happening here?
-
minmax(200px, 1fr)
ensures each column is at least200px
wide but can grow to fill available space. -
auto-fit
collapses empty tracks if there isn’t enough content. -
auto-fill
reserves space for empty tracks, keeping the layout structure intact.
Clarification:
-
auto-fit
: Shrinks or collapses unused columns when there’s no content. -
auto-fill
: Maintains the grid structure, even if columns are empty. Reserves space for empty columns.
Responsive Grid with Media Queries#
Although CSS Grid handles many responsive scenarios on its own, media queries can still help for more precise control.
1
2
3
4
5
6
7
8
9
10
11
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 columns on large screens */
gap: 1rem;
}
@media (max-width: 768px) {
.grid {
grid-template-columns: 1fr; /* Stacks items into a single column */
}
}
This layout shows:
- 3 columns on desktop screens.
- A single-column stacked layout on tablets or phones (under 768px).
Beyond Media Queries: Container Queries#
Media queries are powerful, but sometimes they’re too broad — what if you want a component to adapt based on its container size, not the entire viewport?
That’s where Container Queries come in. To use container queries:
- Add
container-type
to the parent element. - Write container-specific rules using
@container
.
This is especially useful for component-driven UIs, where layout responsiveness depends on parent size (e.g., sidebar, card wrapper, modal content).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* Parent container with container-type enabled */
.card-grid {
container-type: inline-size;
padding: 1rem;
border: 2px dashed #ccc;
max-width: 100%;
}
/* Default layout (single column) */
.card {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
padding: 1rem;
background: #f8f9fa;
border: 1px solid #ddd;
border-radius: 8px;
}
/* Container Query kicks in above 500px */
@container (min-width: 500px) {
.card {
grid-template-columns: 2fr 1fr;
align-items: center;
}
}
Here’s the HTML structure:
1
2
3
4
5
6
<div class="card-grid">
<div class="card">
<h2>Card Title</h2>
<p>This card layout changes based on its container size.</p>
</div>
</div>
Note: Most modern browsers support container queries (except older Safari/Firefox versions). Always check compatibility if building for production.
Real-World Examples#
Responsive Card Dashboard (Media Queries)#
A simple dashboard grid using grid-template-areas
, minmax()
, and media queries.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
.dashboard {
display: grid;
grid-template-areas:
"sidebar content"
"sidebar widgets";
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr;
gap: 1.5rem;
min-height: 100vh;
}
.sidebar {
grid-area: sidebar;
background: #f0f0f0;
padding: 1rem;
}
.content {
grid-area: content;
background: #fff;
padding: 1rem;
}
.widgets {
grid-area: widgets;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
@media (max-width: 768px) {
.dashboard {
grid-template-areas:
"sidebar"
"content"
"widgets";
grid-template-columns: 1fr;
}
}
1
2
3
4
5
6
7
8
9
<div class="dashboard">
<aside class="sidebar">Sidebar</aside>
<main class="content">Main Content</main>
<section class="widgets">
<div class="widget">Widget 1</div>
<div class="widget">Widget 2</div>
<div class="widget">Widget 3</div>
</section>
</div>
Card Grid with Container Queries#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
.card-wrapper {
container-type: inline-size;
padding: 1rem;
max-width: 100%;
border: 1px solid #ccc;
margin-bottom: 2rem;
}
.dashboard-card {
display: grid;
grid-template-areas:
"title"
"meta"
"content";
grid-template-columns: 1fr;
gap: 1rem;
padding: 1rem;
background: #f9fafb;
border-radius: 0.5rem;
}
.dashboard-card h2 { grid-area: title; }
.dashboard-card .meta { grid-area: meta; }
.dashboard-card .content { grid-area: content; }
@container (min-width: 600px) {
.dashboard-card {
grid-template-areas:
"title meta"
"content content";
grid-template-columns: 2fr 1fr;
}
}
1
2
3
4
5
6
7
8
9
<div class="card-wrapper">
<div class="dashboard-card">
<h2>Dashboard Title</h2>
<div class="meta">User • 5 mins ago</div>
<div class="content">
This card layout changes based on container width. Resize the parent to see it adapt.
</div>
</div>
</div>
Quick Reference: Common Grid Properties#
Here’s a concise summary of essential CSS Grid properties:
Property | Description |
---|---|
grid-template-columns | Defines the number and width of columns in the grid |
grid-template-rows | Defines the number and height of rows in the grid |
gap | Sets spacing between rows and columns (shorthand for row-gap and column-gap ) |
grid-template-areas | Defines named areas for placing grid items visually |
justify-items | Aligns all grid items horizontally within their cells |
align-items | Aligns all grid items vertically within their cells |
place-items | Shorthand for setting both align-items and justify-items
|
justify-self | Aligns an individual item horizontally |
align-self | Aligns an individual item vertically |
place-self | Shorthand for setting both align-self and justify-self
|
grid-auto-rows | Defines row size for implicitly created rows |
grid-auto-columns | Defines column size for implicitly created columns |
grid-column | Specifies how many columns an item spans or where it starts/ends |
grid-row | Specifies how many rows an item spans or where it starts/ends |
Frequently Asked Questions (FAQ)#
When should I use auto-fit
vs auto-fill
?#
Use auto-fit
when you want empty tracks to collapse and not reserve space — great for wrapping cards that adjust to available space.
Use auto-fill
if you want to maintain the column structure even when there’s no content — helpful for form fields or placeholders.
Can I use Flexbox and Grid together?#
Absolutely! Use Grid for layout structure (e.g., page, sections), and Flexbox for aligning content within grid items (e.g., buttons inside cards).
Should I replace all media queries with container queries?#
No — container queries are best for component-based layouts. Use media queries for global changes (headers, nav, grid size) and container queries for components inside resizable areas.
Do I still need breakpoints?#
Yes — but you’ll need fewer. Grid’s flexibility (with fr
, minmax()
, and auto-fit
) reduces reliance on rigid breakpoints.
Conclusion#
🎉 Congratulations! You’ve completed the CSS Grid Fundamentals Series.
Let’s recap what you now know:
- ✅ Part 1: The building blocks — containers, tracks, and structure
- ✅ Part 2: Layout precision — grid areas, alignment, spanning, and track creation
- ✅ Part 3: Flexibility — responsive units (
fr
,minmax()
), smart auto-wrapping, media queries, and container queries
With these tools, you can:
- Create flexible layouts without bloated media query chains
- Build components that respond to their own size using container queries
- Design responsive grids that scale gracefully and look professional at every breakpoint
CSS Grid isn’t just a layout tool — it’s a complete design system built into the browser. Mastering it means writing less CSS while building better UI.
🚀 Keep experimenting with combinations of Grid, Flexbox, and container queries — that’s where layout magic happens.