Grid Item Placement: Lines, Spans & Areas
Introduction to Grid Item Placement
In the previous lesson, you learned how to set up a grid container by defining tracks, gaps, and templates. Now it is time to take control of where individual items are placed within that grid. By default, grid items are auto-placed into the next available cell, flowing row by row or column by column depending on grid-auto-flow. But the real power of CSS Grid comes from explicit placement -- telling each item exactly which grid lines it should start and end at, how many tracks it should span, and which named area it belongs to.
Grid item placement is what makes CSS Grid a true two-dimensional layout system. While the container properties define the structure of the grid (how many tracks, what sizes), the item placement properties control where each piece of content lives within that structure. You can place items anywhere in the grid, overlap them, span them across multiple rows and columns, and even place them outside the explicit grid to trigger implicit track creation.
In this lesson, you will master every grid item placement property: grid-column-start, grid-column-end, grid-row-start, grid-row-end, and their shorthands grid-column, grid-row, and grid-area. You will learn how to use line numbers (positive and negative), the span keyword, named lines, named areas, overlapping items, and individual item alignment with justify-self, align-self, and place-self. We will also build practical layouts including magazine-style pages and asymmetric grids.
Understanding Grid Line Numbers
Every grid has numbered lines. Grid line numbering starts at 1 (not 0) and increases from left to right for column lines and from top to bottom for row lines. A grid with 3 columns has 4 column lines (1, 2, 3, 4). A grid with 4 rows has 5 row lines (1, 2, 3, 4, 5). These line numbers are the fundamental way to tell an item where to sit in the grid.
Example: Grid Line Numbers Visualized
/*
Column Lines: 1 2 3 4
| | | |
Row Line 1 --- +-------+-------+-------+
| (1,1) | (1,2) | (1,3) |
Row Line 2 --- +-------+-------+-------+
| (2,1) | (2,2) | (2,3) |
Row Line 3 --- +-------+-------+-------+
| (3,1) | (3,2) | (3,3) |
Row Line 4 --- +-------+-------+-------+
Line 1 = start edge of the first track
Line 4 (column) = end edge of the last column track
Line 4 (row) = end edge of the last row track
*/
.grid {
display: grid;
grid-template-columns: 200px 200px 200px;
grid-template-rows: 100px 100px 100px;
}
grid-column-start and grid-column-end
The grid-column-start property specifies which column line an item starts at, and grid-column-end specifies which column line it ends at. The item occupies all column tracks between these two lines. If you only specify grid-column-start without an end, the item spans exactly one track by default.
Example: Placing Items with Column Lines
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 100px);
gap: 10px;
}
/* Item starts at column line 1, ends at column line 3 (spans 2 columns) */
.item-a {
grid-column-start: 1;
grid-column-end: 3;
}
/* Item starts at column line 2, ends at column line 5 (spans 3 columns) */
.item-b {
grid-column-start: 2;
grid-column-end: 5;
}
/* Item at a specific single column (column 3) */
.item-c {
grid-column-start: 3;
grid-column-end: 4;
/* Or simply: grid-column-start: 3; (defaults to spanning 1 track) */
}
grid-row-start and grid-row-end
The grid-row-start and grid-row-end properties work identically to their column counterparts but control vertical placement. They specify which row lines an item starts and ends at.
Example: Placing Items with Row Lines
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(4, 80px);
gap: 10px;
}
/* Item spans rows 1 to 3 (two rows) */
.sidebar {
grid-row-start: 1;
grid-row-end: 3;
}
/* Item spans rows 2 to 5 (three rows) */
.tall-item {
grid-row-start: 2;
grid-row-end: 5;
}
/* Combining row and column placement */
.featured {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 3;
/* This item occupies a 2x2 area in the top-left corner */
}
The grid-column and grid-row Shorthands
Writing separate start and end properties is verbose. The grid-column shorthand combines grid-column-start and grid-column-end with a forward slash separator. The grid-row shorthand does the same for rows. The syntax is: start-line / end-line.
Example: Using grid-column and grid-row Shorthands
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 100px);
gap: 10px;
}
/* Spans columns 1-3, row 1 only */
.header {
grid-column: 1 / 4; /* Start at line 1, end at line 4 */
grid-row: 1 / 2; /* Start at line 1, end at line 2 */
}
/* Spans column 1, rows 2-4 */
.sidebar {
grid-column: 1 / 2;
grid-row: 2 / 4;
}
/* Spans columns 2-4, rows 2-3 */
.content {
grid-column: 2 / 5;
grid-row: 2 / 3;
}
/* Single cell: column 2, row 3 */
.widget {
grid-column: 2 / 3;
grid-row: 3 / 4;
}
grid-column: 3), it sets only the start line. The item will span one track from that line. This is equivalent to grid-column: 3 / 4 if you have at least 3 column tracks.The span Keyword
Instead of specifying exact start and end line numbers, you can use the span keyword to tell an item how many tracks to span. This is often more intuitive and maintainable than calculating line numbers, especially in responsive layouts. The span keyword can be used with either the start or end value.
Example: Using the span Keyword
.grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-auto-rows: minmax(100px, auto);
gap: 10px;
}
/* Span 3 columns starting from the auto-placed position */
.wide-item {
grid-column: span 3;
/* Equivalent to: grid-column-end: span 3; */
/* Item starts wherever auto-placement puts it, spans 3 columns */
}
/* Start at column 2, span 4 columns (ends at line 6) */
.specific-span {
grid-column: 2 / span 4;
/* Starts at line 2, spans 4 tracks, ends at line 6 */
}
/* Span 2 rows */
.tall-item {
grid-row: span 2;
}
/* Start at a specific line, span backward */
.backward-span {
grid-column: span 2 / 5;
/* Ends at line 5, spans 2 columns backward, starts at line 3 */
}
/* Span both directions */
.large-item {
grid-column: span 2;
grid-row: span 2;
/* Creates a 2x2 block wherever auto-placement puts it */
}
/* Full-width item spanning all columns */
.full-width {
grid-column: 1 / -1; /* Line 1 to the last line */
/* Or: grid-column: span 6; if you know there are 6 columns */
}
span without a start line lets auto-placement find the best position. This is ideal for masonry-style layouts where items of different sizes need to fill in wherever they fit. Combine span with grid-auto-flow: dense on the container for the best gap-filling behavior.Negative Line Numbers
Grid line numbers can also be negative, counting from the end of the explicit grid. The last line is -1, the second-to-last is -2, and so on. Negative line numbers are extremely useful for spanning to the edge of the grid without knowing the exact number of tracks.
Example: Using Negative Line Numbers
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 100px);
gap: 10px;
}
/* Span the full width: line 1 to the last line */
.full-width {
grid-column: 1 / -1;
/* -1 is the last column line (line 5 in a 4-column grid) */
}
/* Last two columns */
.last-two {
grid-column: -3 / -1;
/* From the 3rd-to-last line to the last line = last 2 columns */
}
/* Last column only */
.last-column {
grid-column: -2 / -1;
}
/* Full height: first row line to last row line */
.full-height {
grid-row: 1 / -1;
}
/* Bottom-right corner cell */
.corner {
grid-column: -2 / -1;
grid-row: -2 / -1;
}
/* Everything except the first column */
.skip-first {
grid-column: 2 / -1;
}
grid-template-columns and grid-template-rows. They do not extend into implicit grid tracks. If your grid has 3 explicit columns and an item creates a 4th implicit column, -1 still refers to the end of the 3rd explicit column, not the end of the 4th implicit column.The grid-area Shorthand
The grid-area property is the ultimate shorthand for placing a grid item. It can be used in two different ways: as a line-based shorthand that combines all four placement values, or as a reference to a named area defined in grid-template-areas.
Line-Based grid-area
When using line numbers, grid-area takes four values separated by forward slashes in this order: row-start / column-start / row-end / column-end. Notice the order: it goes row-start, column-start, row-end, column-end (not the row pair then column pair as you might expect).
Example: grid-area with Line Numbers
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 100px);
gap: 10px;
}
/* grid-area: row-start / col-start / row-end / col-end */
/* Top-left 2x2 block */
.item-a {
grid-area: 1 / 1 / 3 / 3;
/* row-start: 1, col-start: 1, row-end: 3, col-end: 3 */
}
/* Full-width header */
.header {
grid-area: 1 / 1 / 2 / -1;
/* Row 1, spans all columns */
}
/* Using span in grid-area */
.item-b {
grid-area: 2 / 2 / span 2 / span 3;
/* Starts at row 2, col 2, spans 2 rows and 3 columns */
}
/* Bottom-right corner */
.item-c {
grid-area: -2 / -2 / -1 / -1;
/* Last row, last column */
}
Named Area grid-area
When the grid container uses grid-template-areas, you can place items by simply referencing the area name with grid-area. This is the most readable and maintainable approach for page-level layouts.
Example: grid-area with Named Areas
.grid {
display: grid;
grid-template-areas:
"header header header"
"sidebar content aside"
"footer footer footer";
grid-template-columns: 200px 1fr 180px;
grid-template-rows: 80px 1fr 60px;
gap: 10px;
min-height: 100vh;
}
/* Place items by area name -- clean and readable */
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
/* The grid-template-areas string creates implicit named lines:
"header" area creates header-start and header-end lines
This means you can also reference them as lines:
grid-column: header-start / header-end; */
grid-template-areas, the browser automatically creates named lines around that area: header-start and header-end for both row and column directions. You can use these implicit line names with grid-column and grid-row if you prefer line-based placement over area-based placement.Overlapping Grid Items
Unlike Flexbox, CSS Grid allows items to overlap by placing them in the same cells. When items overlap, they stack according to their source order by default, with later items on top. You can control the stacking order with the z-index property, which works on grid items without needing position: relative.
Example: Overlapping Items
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 150px);
gap: 0;
}
/* Background image spanning the entire grid */
.background-image {
grid-area: 1 / 1 / -1 / -1;
z-index: 1;
}
/* Text overlay on top of the image */
.text-overlay {
grid-area: 2 / 2 / 3 / 4;
z-index: 2;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 20px;
display: flex;
align-items: center;
justify-content: center;
}
/* Badge in the corner */
.badge {
grid-area: 1 / -2 / 2 / -1;
z-index: 3;
background: var(--primary);
color: white;
padding: 10px;
text-align: center;
}
Example: Overlapping Cards with Offset Effect
.overlap-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: repeat(4, 80px);
gap: 0;
}
.card-1 {
grid-area: 1 / 1 / 3 / 4;
z-index: 1;
background: var(--bg-white);
border: 1px solid var(--border-light);
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.card-2 {
grid-area: 2 / 3 / 4 / 6;
z-index: 2;
background: var(--primary-light);
border: 1px solid var(--primary);
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.card-3 {
grid-area: 3 / 2 / 5 / 5;
z-index: 3;
background: var(--bg-white);
border: 1px solid var(--border-light);
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
z-index works on grid items without position: relative is a unique advantage of Grid layout. Grid items establish a new stacking context automatically when z-index is applied.Individual Item Alignment: justify-self and align-self
By default, grid items stretch to fill their entire grid area (both horizontally and vertically). The justify-self and align-self properties let you override this for individual items, controlling how the item is positioned within its cell or area.
Example: justify-self (Horizontal Alignment within Cell)
.grid {
display: grid;
grid-template-columns: repeat(3, 200px);
grid-template-rows: repeat(2, 150px);
gap: 10px;
}
/* Default: item stretches to fill the cell width */
.item-stretch {
justify-self: stretch; /* Default value */
}
/* Align to the start (left in LTR, right in RTL) */
.item-start {
justify-self: start;
/* Item shrinks to its content width, sits at the left of its cell */
}
/* Align to the end (right in LTR, left in RTL) */
.item-end {
justify-self: end;
}
/* Center horizontally within the cell */
.item-center {
justify-self: center;
}
Example: align-self (Vertical Alignment within Cell)
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 200px;
gap: 10px;
}
/* Default: item stretches to fill the cell height */
.item-stretch {
align-self: stretch; /* Default value */
}
/* Align to the top of the cell */
.item-top {
align-self: start;
}
/* Align to the bottom of the cell */
.item-bottom {
align-self: end;
}
/* Center vertically within the cell */
.item-middle {
align-self: center;
}
The place-self Shorthand
The place-self shorthand combines align-self and justify-self in one declaration. The syntax is place-self: <align-self> <justify-self>. If you provide a single value, it applies to both axes.
Example: Using place-self
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 200px;
gap: 10px;
}
/* Center both horizontally and vertically */
.centered-item {
place-self: center;
/* Equivalent to: align-self: center; justify-self: center; */
}
/* Top-right corner of cell */
.top-right {
place-self: start end;
/* align-self: start (top), justify-self: end (right) */
}
/* Bottom-left corner of cell */
.bottom-left {
place-self: end start;
/* align-self: end (bottom), justify-self: start (left) */
}
/* Stretch vertically, center horizontally */
.stretch-center {
place-self: stretch center;
}
justify-self or align-self with any value other than stretch, the item shrinks to its content size in that direction. This means the item no longer fills the entire cell. The item's size is determined by its content, any explicit width/height, or min-width/min-height properties.The order Property in Grid
Just like in Flexbox, the order property in Grid controls the visual order of auto-placed items. Items with lower order values are placed first. The default value is 0. This only affects auto-placed items -- explicitly placed items (those with grid-column, grid-row, or grid-area) always go to their specified positions regardless of order.
Example: order in Grid
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
gap: 10px;
}
/* These items are auto-placed, so order affects them */
.item-first { order: -1; } /* Placed first */
.item-normal { order: 0; } /* Default order */
.item-last { order: 1; } /* Placed last */
/* This item is explicitly placed, order is ignored for placement */
.explicit-item {
grid-column: 2 / 3;
grid-row: 1 / 2;
order: 99; /* Does not change its position -- it is explicitly placed */
}
order property only changes visual order, not DOM order. Screen readers and keyboard navigation follow the source order. Use order only for presentational adjustments that do not affect the logical reading order.Practical Example: Magazine Layout
Magazine layouts feature asymmetric arrangements with featured articles spanning multiple columns and rows, surrounded by smaller articles. This is where Grid truly shines.
Example: Magazine-Style Layout
<div class="magazine">
<article class="featured">Featured Article</article>
<article class="article-1">Article 1</article>
<article class="article-2">Article 2</article>
<article class="article-3">Article 3</article>
<article class="article-4">Article 4</article>
<article class="article-5">Article 5</article>
</div>
CSS for Magazine Layout
.magazine {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: minmax(150px, auto);
gap: 16px;
padding: 16px;
}
/* Featured article: large, spanning 2 columns and 2 rows */
.featured {
grid-column: 1 / 3;
grid-row: 1 / 3;
background: var(--primary);
color: white;
padding: 32px;
border-radius: 12px;
font-size: 1.5rem;
}
/* Article 1: top-right, single cell */
.article-1 {
grid-column: 3 / 4;
grid-row: 1 / 2;
background: var(--bg-white);
padding: 20px;
border-radius: 8px;
border: 1px solid var(--border-light);
}
/* Article 2: right of article 1, tall */
.article-2 {
grid-column: 4 / 5;
grid-row: 1 / 3;
background: var(--bg-light);
padding: 20px;
border-radius: 8px;
}
/* Article 3: below article 1 */
.article-3 {
grid-column: 3 / 4;
grid-row: 2 / 3;
background: var(--bg-white);
padding: 20px;
border-radius: 8px;
border: 1px solid var(--border-light);
}
/* Article 4 and 5: full-width row at the bottom */
.article-4 {
grid-column: 1 / 3;
background: var(--bg-white);
padding: 20px;
border-radius: 8px;
border: 1px solid var(--border-light);
}
.article-5 {
grid-column: 3 / -1;
background: var(--primary-light);
padding: 20px;
border-radius: 8px;
}
/* Responsive: stack on mobile */
@media (max-width: 768px) {
.magazine {
grid-template-columns: 1fr;
}
.featured,
.article-1,
.article-2,
.article-3,
.article-4,
.article-5 {
grid-column: 1 / -1;
grid-row: auto;
}
}
Practical Example: Asymmetric Image Grid
Asymmetric grids create visual interest by placing items of different sizes in an intentionally unbalanced layout. This is popular for portfolio sites, image galleries, and landing pages.
Example: Asymmetric Image Grid
<div class="image-grid">
<div class="img-large"><img src="photo-1.jpg" alt="Large photo"></div>
<div class="img-small-1"><img src="photo-2.jpg" alt="Small photo"></div>
<div class="img-small-2"><img src="photo-3.jpg" alt="Small photo"></div>
<div class="img-medium"><img src="photo-4.jpg" alt="Medium photo"></div>
<div class="img-tall"><img src="photo-5.jpg" alt="Tall photo"></div>
</div>
CSS for Asymmetric Image Grid
.image-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(4, 150px);
gap: 12px;
}
.image-grid img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 8px;
}
/* Large image: top-left, 2x2 */
.img-large {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
/* Two small images stacked on the right */
.img-small-1 {
grid-column: 3 / 4;
grid-row: 1 / 2;
}
.img-small-2 {
grid-column: 3 / 4;
grid-row: 2 / 3;
}
/* Medium image: bottom-left, 1 column wide, 2 rows tall */
.img-medium {
grid-column: 1 / 2;
grid-row: 3 / 5;
}
/* Tall image: bottom-right, 2 columns wide */
.img-tall {
grid-column: 2 / 4;
grid-row: 3 / 5;
}
Practical Example: Pricing Table with Grid
A pricing table is another excellent use case for Grid item placement. You can align the plans side by side, highlight a featured plan by making it span more rows, and ensure consistent alignment of features across all plans.
Example: Pricing Table Layout
<div class="pricing-grid">
<div class="plan basic">
<h3>Basic</h3>
<p class="price">$9/mo</p>
<ul>
<li>5 Projects</li>
<li>10 GB Storage</li>
<li>Email Support</li>
</ul>
<button>Choose Basic</button>
</div>
<div class="plan pro">
<h3>Pro</h3>
<p class="price">$29/mo</p>
<ul>
<li>Unlimited Projects</li>
<li>100 GB Storage</li>
<li>Priority Support</li>
<li>Advanced Analytics</li>
</ul>
<button>Choose Pro</button>
</div>
<div class="plan enterprise">
<h3>Enterprise</h3>
<p class="price">$99/mo</p>
<ul>
<li>Unlimited Everything</li>
<li>1 TB Storage</li>
<li>24/7 Phone Support</li>
</ul>
<button>Choose Enterprise</button>
</div>
</div>
CSS for Pricing Table
.pricing-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
padding: 40px 20px;
align-items: start;
}
.plan {
background: var(--bg-white);
border: 1px solid var(--border-light);
border-radius: 12px;
padding: 32px 24px;
text-align: center;
}
/* Featured plan: visually elevated */
.plan.pro {
border: 2px solid var(--primary);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
transform: scale(1.05);
position: relative;
z-index: 1;
/* Using align-self to stretch it taller */
align-self: stretch;
}
.plan .price {
font-size: 2.5rem;
font-weight: 700;
color: var(--primary);
margin: 16px 0;
}
.plan button {
width: 100%;
padding: 12px;
background: var(--primary);
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
margin-top: 24px;
}
/* Responsive: stack on mobile */
@media (max-width: 768px) {
.pricing-grid {
grid-template-columns: 1fr;
max-width: 400px;
margin: 0 auto;
}
.plan.pro {
transform: none;
order: -1; /* Show featured plan first on mobile */
}
}
Practical Example: Photo Gallery with Featured Images
This pattern combines auto-placement with explicit placement to create a gallery where certain images are featured (larger) while others fill in around them automatically.
Example: Gallery with Featured Images
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 200px;
grid-auto-flow: dense; /* Fill in gaps */
gap: 8px;
}
.gallery img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 4px;
}
/* Regular images: auto-placed, 1x1 */
.gallery .photo {
/* No explicit placement needed -- auto-placed */
}
/* Featured: 2x2 */
.gallery .photo.featured {
grid-column: span 2;
grid-row: span 2;
}
/* Wide: 2 columns, 1 row */
.gallery .photo.wide {
grid-column: span 2;
}
/* Tall: 1 column, 2 rows */
.gallery .photo.tall {
grid-row: span 2;
}
/* With dense packing, small photos automatically fill
the gaps left by featured, wide, and tall photos */
Practical Example: Dashboard Widget Layout
Dashboard widgets often need precise placement with some widgets being larger than others. Grid item placement makes this straightforward to build and maintain.
Example: Dashboard Widget Placement
.dashboard {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-auto-rows: minmax(80px, auto);
gap: 16px;
padding: 16px;
}
/* Full-width header widget */
.widget-header {
grid-column: 1 / -1;
}
/* Stats widgets: 3 columns each, in a row of 4 */
.widget-stat {
grid-column: span 3;
}
/* Main chart: 8 columns wide, 3 rows tall */
.widget-chart {
grid-column: 1 / 9;
grid-row: span 3;
}
/* Activity feed: 4 columns, 3 rows */
.widget-activity {
grid-column: 9 / -1;
grid-row: span 3;
}
/* Table: full width */
.widget-table {
grid-column: 1 / -1;
grid-row: span 2;
}
/* Small info widgets */
.widget-info {
grid-column: span 4;
}
/* Responsive breakpoints */
@media (max-width: 1024px) {
.widget-chart {
grid-column: 1 / -1;
}
.widget-activity {
grid-column: 1 / -1;
}
.widget-stat {
grid-column: span 6;
}
}
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr;
}
.widget-stat,
.widget-chart,
.widget-activity,
.widget-table,
.widget-info {
grid-column: 1 / -1;
}
}
Placement with Named Grid Lines
If you defined named lines on your grid container (as covered in the previous lesson), you can reference those names when placing items. Named lines make your placement code much more readable.
Example: Placing Items with Named Lines
.grid {
display: grid;
grid-template-columns:
[full-start] 1fr
[content-start] minmax(0, 800px)
[content-end] 1fr
[full-end];
grid-template-rows:
[header-start] auto
[header-end main-start] 1fr
[main-end footer-start] auto
[footer-end];
min-height: 100vh;
}
/* Full-width header */
.header {
grid-column: full-start / full-end;
grid-row: header-start / header-end;
}
/* Centered content */
.main-content {
grid-column: content-start / content-end;
grid-row: main-start / main-end;
}
/* Full-width footer */
.footer {
grid-column: full-start / full-end;
grid-row: footer-start / footer-end;
}
/* Full-bleed element within the content area */
.full-bleed-image {
grid-column: full-start / full-end;
/* This stretches from edge to edge while other content is centered */
}
Example: 12-Column Grid with Named Lines
.grid {
display: grid;
grid-template-columns: repeat(12, [col] 1fr);
gap: 20px;
}
/* Span columns 1-8 using named line with index */
.main-content {
grid-column: col 1 / col 9;
/* Starts at the 1st "col" line, ends at the 9th "col" line */
/* This spans 8 columns */
}
/* Span columns 9-12 */
.sidebar {
grid-column: col 9 / -1;
/* From the 9th "col" line to the end */
}
/* Full width */
.banner {
grid-column: col 1 / -1;
}
Common Placement Patterns
Here is a quick reference of placement patterns you will use frequently.
Quick Reference: Placement Patterns
/* Full width (spans all columns) */
.full { grid-column: 1 / -1; }
/* Center columns (in a 12-col grid) */
.centered-6 { grid-column: 4 / 10; } /* 6 cols centered */
.centered-8 { grid-column: 3 / 11; } /* 8 cols centered */
/* Two-thirds / one-third split */
.two-thirds { grid-column: span 8; }
.one-third { grid-column: span 4; }
/* Half and half */
.half { grid-column: span 6; }
/* Explicit 2x2 block */
.block-2x2 {
grid-column: span 2;
grid-row: span 2;
}
/* Pin to bottom-right corner */
.bottom-right {
grid-column: -2 / -1;
grid-row: -2 / -1;
}
/* First column, all rows */
.first-col-full {
grid-column: 1 / 2;
grid-row: 1 / -1;
}
/* Last row, all columns */
.last-row-full {
grid-column: 1 / -1;
grid-row: -2 / -1;
}
/* Center a single item in its cell */
.item-centered {
place-self: center;
}
Debugging Grid Placement
When grid items do not appear where you expect, here are the most common causes and how to fix them.
Common Grid Placement Issues
/* Issue 1: Item placed outside the explicit grid */
.grid {
grid-template-columns: repeat(3, 1fr); /* 4 column lines */
}
.item {
grid-column: 5 / 7; /* Lines 5-7 do not exist in the explicit grid */
/* Browser creates implicit columns to accommodate this item */
/* Fix: ensure your line numbers match your grid definition */
}
/* Issue 2: Overlapping items unintentionally */
.item-a { grid-column: 1 / 3; grid-row: 1 / 2; }
.item-b { grid-column: 2 / 4; grid-row: 1 / 2; }
/* Both items occupy column 2, row 1 -- they overlap! */
/* Fix: adjust line numbers so items do not share the same cells */
/* Issue 3: Negative line numbers not working as expected */
.grid {
grid-template-columns: repeat(3, 1fr);
/* Explicit grid has lines 1-4 */
}
.item {
grid-column: 1 / -1; /* Works: spans lines 1-4 (all 3 columns) */
}
/* But if items create implicit columns, -1 still means explicit line 4 */
/* Issue 4: span does not work with explicit start AND end */
.item {
grid-column: 2 / span 3; /* Works: start at 2, span 3 */
grid-column: span 2 / 5; /* Works: end at 5, span 2 backward */
/* grid-column: span 2 / span 3; -- INVALID: cannot span from both sides */
}
/* Tip: Use browser DevTools to visualize the grid */
/* Chrome, Firefox, and Edge all have excellent grid inspectors */
/* They show line numbers, areas, and gaps visually */
Grid vs Flexbox: When to Use Which
Now that you know both Grid and Flexbox, understanding when to use each is crucial for writing clean, maintainable CSS.
- Use Grid when: You need control over both rows AND columns simultaneously. Page-level layouts, dashboard panels, magazine layouts, image galleries with mixed sizes, form layouts with aligned labels and inputs, any two-dimensional arrangement.
- Use Flexbox when: You are working in one direction at a time. Navigation bars, button groups, card content (vertical stack inside a card), centering a single item, media objects (image + text), distributing items along a single axis.
- Use both together: Grid for the overall page layout, Flexbox for component-level layouts within grid cells. A grid cell might contain a card, and that card uses Flexbox to arrange its internal elements vertically.
Example: Grid and Flexbox Together
/* Grid for the page layout */
.page {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
/* Flexbox for the navigation inside a grid cell */
.nav-sidebar {
grid-row: 2 / 3;
display: flex;
flex-direction: column;
gap: 4px;
padding: 20px;
}
/* Flexbox for card layout inside a grid cell */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}
.card {
display: flex; /* Flexbox inside the grid item */
flex-direction: column;
padding: 20px;
border-radius: 8px;
background: var(--bg-white);
}
.card-body {
flex: 1; /* Content grows */
}
.card-footer {
margin-top: auto; /* Footer pushed to bottom */
}
Practice Exercise
Build a magazine-style article page using CSS Grid. Create a grid container with grid-template-columns: repeat(12, 1fr) and grid-auto-rows: minmax(80px, auto). Place a featured article that spans columns 1 through 8 and rows 1 through 3. Place a sidebar that spans columns 9 through the last line and rows 1 through 5. Add three smaller article cards below the featured article, each spanning 4 columns. Below all articles, add a full-width banner that uses grid-column: 1 / -1. Use z-index to overlap a "BREAKING" label badge over the top-right corner of the featured article. Apply place-self: center to center the badge text within its area. Add a responsive breakpoint at 768px that changes the grid to a single column layout by setting all items to grid-column: 1 / -1 and grid-row: auto. Finally, use align-self: start on the sidebar to prevent it from stretching to match the height of its row span, and use justify-self: stretch on all article cards to ensure they fill their column allocations.