grid auto-sizing & minmax
The minmax() function defines minimum and maximum track sizes, enabling responsive grids without media queries. Combined with auto-fit or auto-fill, minmax() creates grids that automatically adjust column count based on available space. This is one of grid's most powerful features.
minmax() function
/* minmax(minimum, maximum) */
grid-template-columns: minmax(200px, 1fr);
/* Column is at least 200px, at most 1fr of available space */
/* Multiple columns with minmax */
.grid {
display: grid;
grid-template-columns: minmax(100px, 200px) minmax(50px, 100px);
/* First column: 100px-200px, Second: 50px-100px */
}
/* With flex units -->
.grid {
display: grid;
grid-template-columns: minmax(300px, 2fr) minmax(200px, 1fr);
/* First column: min 300px, max 2/3 of space */
/* Second column: min 200px, max 1/3 of space */
}auto-fit with minmax: responsive grid
The combination of auto-fit and minmax() is incredibly powerful. It creates a grid that automatically adjusts the number of columns based on viewport width.
/* Auto-fit responsive grid */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
<!-- Behavior: creates as many 250px columns as fit -->
<!-- Wide screen (1200px): 4 columns
Tablet (768px): 3 columns
Phone (375px): 1 column
All without media queries! -->
/* Slightly larger minimum */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 15px;
}
<!-- Wide: 3-4 columns
Medium: 2 columns
Narrow: 1 column -->
/* Smaller minimum for more columns -->
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 10px;
}
<!-- Creates many small columns -->
<!-- 6+ columns on wide screens, scales down -->
/* With maximum width -->
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
max-width: 1400px; /* container max width -->
margin: 0 auto;
}
<!-- Limits grid width, adds responsive columns -->auto-fill vs auto-fit
Feature | auto-fit | auto-fill |
|---|---|---|
Creates tracks | Only as many as needed | As many as fit in container |
Empty tracks | Collapses empty tracks | Leaves empty tracks |
Best for | Content-based layouts | Even distribution |
Common use | Most layouts | Less common |
<!-- With auto-fit: empty tracks collapse -->
.grid-fit {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}
<!-- If container is 600px:
Fits 3 columns
If 3 items: 200px each (expanded to fill)
[Item 1 ] [Item 2 ] [Item 3 ] -->
<!-- With auto-fill: keeps track slots -->
.grid-fill {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
}
<!-- If container is 600px:
Creates 3 column tracks (even if items don't fill)
[Item 1] [Item 2] [Item 3]
[─────] [─────] [─────] (tracks exist, empty) -->
<!-- auto-fit is usually preferred for most layouts -->Practical responsive grids
<!-- E-commerce product grid -->
<div class="products">
<div class="product-card">Product</div>
<!-- many products -->
</div>
.products {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
padding: 20px;
}
.product-card {
border: 1px solid #eeeeee;
border-radius: 8px;
overflow: hidden;
}
<!-- Automatically 4-5 columns on desktop,
2-3 on tablet, 1 on mobile -->
<!-- Article grid with varying item sizes -->
<div class="articles">
<article class="featured">Featured</article>
<article>Article</article>
<!-- many articles -->
</div>
.articles {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 25px;
}
.featured {
grid-column: span 2; /* takes 2 columns -->
min-height: 400px;
}
article {
min-height: 200px;
}
<!-- Featured article is larger, others scale responsively -->
<!-- Dashboard widgets -->
<div class="dashboard">
<div class="widget">Widget</div>
<!-- many widgets -->
</div>
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
padding: 20px;
}
.widget {
background: white;
border: 1px solid #ddd;
padding: 20px;
border-radius: 6px;
}Combining minmax with other functions
<!-- minmax with clamp -->
.grid {
display: grid;
gap: clamp(10px, 5vw, 30px); /* gap scales with viewport -->
}
<!-- minmax with calc -->
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(calc(250px + 2vw), 1fr));
/* Minimum size changes with viewport -->
}
<!-- Limiting maximum width with minmax -->
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, min(1fr, 350px)));
/* Each column maxes out at 350px -->
}
<!-- Multiple columns with different rules -->
.grid {
display: grid;
grid-template-columns:
minmax(200px, 1fr) /* sidebar: 200px-1fr */
minmax(300px, 2fr); /* content: 300px-2fr */
}When to use explicit vs auto sizing
Use case | Approach |
|---|---|
Responsive product grid | repeat(auto-fit, minmax(250px, 1fr)) |
Fixed sidebar + content | minmax(250px, 1fr) 1fr |
Complex dashboard | Explicit columns + areas |
Card grid (no fixed ratio) | repeat(auto-fit, minmax(200px, 1fr)) |
Precise layout control | Named areas or explicit placement |