CSS Grid's auto-placement creates responsive layouts without media queries. Here's how to use it.
Auto-Fill vs Auto-Fit#
1/* auto-fill: creates as many tracks as fit */
2.grid-auto-fill {
3 display: grid;
4 grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
5 gap: 1rem;
6}
7/* Creates columns even if empty */
8
9/* auto-fit: collapses empty tracks */
10.grid-auto-fit {
11 display: grid;
12 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
13 gap: 1rem;
14}
15/* Remaining items expand to fill space */
16
17/* Key difference: */
18/* auto-fill: [200px] [200px] [200px] [empty] [empty] */
19/* auto-fit: [333px] [333px] [333px] (no empty tracks) */
20
21/* When to use which: */
22.gallery {
23 /* auto-fit for responsive cards that expand */
24 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
25}
26
27.icon-grid {
28 /* auto-fill for fixed-size icons */
29 grid-template-columns: repeat(auto-fill, 48px);
30}Minmax Function#
1/* Flexible column sizing */
2.flexible-grid {
3 display: grid;
4 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
5 gap: 1.5rem;
6}
7
8/* Fixed minimum, flexible maximum */
9.cards {
10 grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
11}
12
13/* Percentage minimum */
14.responsive {
15 grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
16}
17
18/* With clamp for more control */
19.advanced {
20 grid-template-columns: repeat(
21 auto-fit,
22 minmax(clamp(200px, 30%, 400px), 1fr)
23 );
24}
25
26/* Fixed max */
27.fixed-max {
28 grid-template-columns: repeat(auto-fill, minmax(200px, 300px));
29}Implicit Grid#
1/* Grid creates rows automatically */
2.auto-rows {
3 display: grid;
4 grid-template-columns: repeat(3, 1fr);
5 grid-auto-rows: 200px; /* Height of auto-created rows */
6 gap: 1rem;
7}
8
9/* Variable row heights */
10.variable-rows {
11 grid-template-columns: repeat(3, 1fr);
12 grid-auto-rows: minmax(100px, auto);
13}
14
15/* Auto columns for horizontal flow */
16.auto-columns {
17 display: grid;
18 grid-auto-flow: column;
19 grid-auto-columns: 200px;
20 grid-template-rows: repeat(3, 1fr);
21 gap: 1rem;
22}
23
24/* Dense packing */
25.dense-grid {
26 display: grid;
27 grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
28 grid-auto-flow: dense; /* Fill gaps with smaller items */
29 gap: 1rem;
30}Responsive Card Grid#
1/* Basic card grid */
2.card-grid {
3 display: grid;
4 grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
5 gap: 2rem;
6 padding: 2rem;
7}
8
9.card {
10 background: white;
11 border-radius: 8px;
12 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
13 overflow: hidden;
14}
15
16/* Cards with fixed aspect ratio images */
17.card-image {
18 aspect-ratio: 16 / 9;
19 object-fit: cover;
20 width: 100%;
21}
22
23.card-content {
24 padding: 1.5rem;
25}
26
27/* Featured card spanning multiple columns */
28.card.featured {
29 grid-column: span 2;
30}
31
32@media (max-width: 600px) {
33 .card.featured {
34 grid-column: span 1;
35 }
36}Masonry-Like Layout#
1/* Varying height items */
2.masonry-grid {
3 display: grid;
4 grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
5 grid-auto-rows: 10px; /* Small row height for precision */
6 gap: 1rem;
7}
8
9.masonry-item {
10 /* Span multiple rows based on content */
11}
12
13.masonry-item.small {
14 grid-row: span 15; /* 150px */
15}
16
17.masonry-item.medium {
18 grid-row: span 25; /* 250px */
19}
20
21.masonry-item.large {
22 grid-row: span 35; /* 350px */
23}
24
25/* JavaScript can dynamically set spans based on content height */Photo Gallery#
1/* Responsive photo gallery */
2.gallery {
3 display: grid;
4 grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
5 grid-auto-rows: 200px;
6 grid-auto-flow: dense;
7 gap: 0.5rem;
8}
9
10.gallery img {
11 width: 100%;
12 height: 100%;
13 object-fit: cover;
14}
15
16/* Landscape images */
17.gallery .landscape {
18 grid-column: span 2;
19}
20
21/* Portrait images */
22.gallery .portrait {
23 grid-row: span 2;
24}
25
26/* Large featured images */
27.gallery .featured {
28 grid-column: span 2;
29 grid-row: span 2;
30}
31
32/* Responsive adjustments */
33@media (max-width: 600px) {
34 .gallery {
35 grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
36 grid-auto-rows: 150px;
37 }
38
39 .gallery .landscape,
40 .gallery .portrait,
41 .gallery .featured {
42 grid-column: span 1;
43 grid-row: span 1;
44 }
45}Dashboard Layout#
1/* Dashboard with auto-placed widgets */
2.dashboard {
3 display: grid;
4 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
5 grid-auto-rows: minmax(200px, auto);
6 gap: 1.5rem;
7 padding: 1.5rem;
8}
9
10.widget {
11 background: white;
12 border-radius: 8px;
13 padding: 1.5rem;
14 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
15}
16
17/* Full-width widgets */
18.widget.full {
19 grid-column: 1 / -1;
20}
21
22/* Wide widgets */
23.widget.wide {
24 grid-column: span 2;
25}
26
27/* Tall widgets */
28.widget.tall {
29 grid-row: span 2;
30}
31
32/* Chart widget */
33.widget.chart {
34 grid-column: span 2;
35 min-height: 400px;
36}
37
38@media (max-width: 768px) {
39 .widget.wide,
40 .widget.chart {
41 grid-column: span 1;
42 }
43}Product Grid#
1/* E-commerce product grid */
2.product-grid {
3 display: grid;
4 grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
5 gap: 1.5rem;
6}
7
8.product-card {
9 display: flex;
10 flex-direction: column;
11 background: white;
12 border-radius: 8px;
13 overflow: hidden;
14 transition: transform 0.2s, box-shadow 0.2s;
15}
16
17.product-card:hover {
18 transform: translateY(-4px);
19 box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
20}
21
22.product-image {
23 aspect-ratio: 1;
24 object-fit: cover;
25}
26
27.product-info {
28 padding: 1rem;
29 flex: 1;
30 display: flex;
31 flex-direction: column;
32}
33
34.product-title {
35 margin: 0 0 0.5rem;
36}
37
38.product-price {
39 margin-top: auto;
40 font-weight: bold;
41 color: #007bff;
42}Auto-Placement Algorithm#
1/* Control placement direction */
2.row-flow {
3 grid-auto-flow: row; /* Default: fill rows first */
4}
5
6.column-flow {
7 grid-auto-flow: column; /* Fill columns first */
8}
9
10/* Dense packing fills gaps */
11.dense {
12 grid-auto-flow: row dense;
13}
14
15/* Example: items placed left-to-right, top-to-bottom */
16.default-placement {
17 display: grid;
18 grid-template-columns: repeat(4, 1fr);
19 grid-auto-rows: 100px;
20}
21
22/* Item order doesn't affect placement unless specified */
23.item:nth-child(1) { /* Row 1, Col 1 */ }
24.item:nth-child(2) { /* Row 1, Col 2 */ }
25/* ... */
26.item:nth-child(5) { /* Row 2, Col 1 */ }
27
28/* Explicit placement takes precedence */
29.item.pinned {
30 grid-column: 3;
31 grid-row: 1;
32}Nested Grids#
1/* Parent grid */
2.outer-grid {
3 display: grid;
4 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
5 gap: 2rem;
6}
7
8/* Nested grid inside items */
9.grid-item {
10 display: grid;
11 grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
12 gap: 0.5rem;
13}
14
15/* Subgrid (when supported) */
16.outer {
17 display: grid;
18 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
19 gap: 1rem;
20}
21
22.inner {
23 display: grid;
24 grid-template-columns: subgrid;
25 grid-column: span 3;
26}Best Practices#
Auto-Placement:
✓ Use auto-fit for expanding items
✓ Use auto-fill for fixed-size items
✓ Set grid-auto-rows for consistent height
✓ Use dense for gap filling
Responsive Design:
✓ Use minmax with fr units
✓ Set appropriate minimum sizes
✓ Test at various viewport widths
✓ Use min() for mobile fallback
Performance:
✓ Avoid too many auto tracks
✓ Limit grid-auto-flow: dense use
✓ Use explicit placement for large grids
✓ Test with many items
Avoid:
✗ Mixing auto-fit with fixed column count
✗ Very small minmax minimums
✗ Forgetting gap property
✗ Over-nesting grids
Conclusion#
CSS Grid auto-placement creates flexible, responsive layouts without media queries. Use auto-fill for fixed-size items that maintain spacing, and auto-fit for items that expand to fill available space. Combine with minmax() for truly responsive grids that adapt to any viewport.