Back to Blog
CSSGridLayoutAuto-placement

CSS Grid Auto-Placement Guide

Master CSS Grid auto-placement for dynamic layouts with auto-fill, auto-fit, and implicit tracks.

B
Bootspring Team
Engineering
March 6, 2020
6 min read

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 */
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.

Share this article

Help spread the word about Bootspring