Can I have a varying number of columns per row in a CSS grid?
Asked Answered
S

6

45

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 100px;
  grid-auto-rows: 60px;
  grid-gap: 15px;
}

.col {
  background-color: tomato;
}
<div class="grid">
  <div class="col"></div>
  <div class="col"></div>
  <div class="col"></div>
  <div class="col"></div>
  <div class="col"></div>
</div>

This creates 2 rows, first is 100px height, second is auto-created with 60px height. 2 columns in the second row have 1fr width.

Is this possible via CSS Grid/Flexbox to horizontally center 2 columns in the 2nd row? I.e. have a varying number of columns per row.

I am stuck trying to solve a trivial usecase for the CSS Grid framework in the browser. This is pretty nonproblematic to achieve if you build your grids with Flexbox.

But can I achieve it with CSS Grid?

Here is a CodePen demo of what I am trying to achieve.

Summon answered 3/12, 2017 at 0:23 Comment(2)
A grid, by definition, has the same number of columns per row. You need flexbox, not grid.Pancreatin
Something like this can be useful: #43962717Chlor
D
52

You're asking this:

Can I have a varying number of columns per row in a CSS Grid?

But then you're saying this:

Is this possible via CSS Grid/Flexbox to horizontally center 2 columns in the 2nd row?

It looks like you're stuck in a classic XY Problem: You're focusing on your attempted solution rather than your actual problem.

Yes, it is possible to center columns (and grid items, and content) in CSS Grid. (See various methods here: Centering in CSS Grid)

No, it's not possible to have a varying number of columns per row in a CSS Grid, or any grid for that matter. Otherwise, you don't have a grid.

Since appearance is often all that matters in a layout, you can build something that looks like three "columns" in the first row and two "columns" in the second row – centered – using CSS Grid.

In my example below, I've divided the horizontal space in the grid container among 12 columns. I've then used Grid's line-based placement features to position and size the items.

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: 40px;
  grid-gap: 10px;
}

.col:nth-child(-1n + 3) {
  grid-column: span 4;
}
.col:nth-last-child(2) {
  grid-row-start: 2;
  grid-column: 3 / span 4;
}
.col:nth-last-child(1) {
  grid-row-start: 2;
  grid-column: 7 / span 4;
}
.col {
  background-color: tomato;
}
<div class="grid">
  <div class="col"></div>
  <div class="col"></div>
  <div class="col"></div>
  <div class="col"></div>
  <div class="col"></div>
</div>

codepen demo

Here's what it looks like using Firefox DevTools:

enter image description here

Dippold answered 3/12, 2017 at 1:17 Comment(3)
This is a really flexible solution when combined with media queries.Furst
Is a generic way to keep this infinity (unknown number of rows which will keep displayed 3, 2, 3, 2.....)Canfield
@MoshFeu, you could set up a pattern by targeting each of the five items for repetition. codepen.io/mbb7774/pen/eYpVgQg?editors=1100Dippold
C
15

If your rows have varying numbers of cells that aren't all laid out on a single two-dimensional (row and column) space, you don't have a grid. A grid by definition contains a fixed number of rows and columns, and cells that span one or more of each. Maybe you'd have multiple heterogeneous grids, one per row, but that just defeats the whole point of grids, really.

If your varying number of rows is symmetrical or follows some kind of pattern, you can follow Michael_B's suggestion of building a grid based on a common denominator and populating the grid areas mosaic-style. This is just about as non-trivial as a flexbox solution currently would be, but once more browsers implement flexbox fragmentation, flexbox should become the obvious choice over grid as it ought to be.

Clueless answered 3/12, 2017 at 0:34 Comment(3)
Oh well that's a bummer, yea, my question doesn't even make sense within this framework. ThanksSummon
@Summon Maybe as a side note, you can set grid-template-rows to auto to lay out a varying number of boxes in the columns. But you couldn't center the second row of boxes like in your example. CSS grids are rather 'rigid'.Atavism
Grids are rigid. Why do people seem to act like these limitations are unique to CSS grids? If anything, CSS grids are less rigid than conventional grids.Clueless
D
8

You could always try it this way:

.container {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: [col] 100px [col] 100px [col] 100px [col] 100px;
  grid-template-rows: [row] auto [row] auto [row];
  background-color: #fff;
  color: #444;
}

.col {
  background-color: #444;
  color: #fff;
  border-radius: 5px;
  padding: 20px;
  font-size: 150%;
}

.a {
  grid-column: col / span 2;
  grid-row: row;
}

.b {
  grid-column: col 3 / span 2;
  grid-row: row;
}

.c {
  grid-column: col;
  grid-row: row 2;
}

.d {
  grid-column: col 2 / span 3;
  grid-row: row 2;
}

.e {
  grid-column: col / span 4;
  grid-row: row 3;
}
<div class="container">
  <div class="col a">A</div>
  <div class="col b">B</div>
  <div class="col c">C</div>
  <div class="col d">D</div>
  <div class="col e">E</div>
</div>

CodePen: https://codepen.io/anon/pen/MOLrvq

Disadvantage answered 3/12, 2017 at 0:38 Comment(0)
P
2

You can solve this with having nested grids. Grid-1 (covers complete area) Grid-2 (covers row-1) Grid-3 (covers row-2)

By having this setting you can shorten the width of row-2.

Pyrene answered 6/4, 2018 at 15:22 Comment(0)
B
0

If anyone is going through this same trouble, this is the way I figured it out. I had two divs inside a container and in wanted them to have different columns. So i just made for each div a grid. And i put 1fr row, and then the number of columns i wanted. It worked like a charm.

Brinton answered 26/7, 2019 at 13:20 Comment(1)
You should add a snippet to your answer to demonstrate what you're describing.Oldham
E
0

I achieve this using grid in child element.

.container {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 5px;
  }
  
  .item {
    background-color: aqua;
    height: 120px;
  }
  
  .item5 {
    display: grid;
    grid-column: 1 / span 2;
    grid-template-columns: 1fr 1fr; /* Divide item5 into 2 equally sized columns */
  }
  
  .item5 > div {
    background-color: aqua;
    height: 310px;
    margin-right: 5px; /* Add margin for gap effect */
  }
   .item5 > div:last-child {
    margin-right: 0;
  }
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="grid.css">
    <title>Grid</title>
</head>
<body>
    <div class="container">
        <div class="item item1"><h1>hello World</h1></div>
        <div class="item item2"><h1>hello World</h1></div>
        <div class="item item3"><h1>hello World</h1></div>
        <div class="item item4"><h1>hello World</h1></div>
        <div class="item5">
            <div>
                <h1>hello World 5</h1>
            </div>
            <div>
                <h1>hello World 5.5</h1>
            </div>
        </div>
        <div class="item item6"><h1>hello World</h1></div>
        <div class="item item7"><h1>hello World</h1></div>
        <div class="item item8"><h1>hello World</h1></div>
        <div class="item item9"><h1>hello World</h1></div>
        <div class="item item10"><h1>hello World</h1></div>
    </div>
</body>
</html>
Enrollment answered 15/8, 2023 at 5:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.