Search code examples
htmlcsscss-grid

CSS Grid - 2x2 grid always taking up the full width when possible


I'm trying to create a 2x2 CSS grid (possibly extended to 3x2 in the future) that only pushes items onto the first row when there are three children in the grid, and I'm not sure if this is possible with grid.

The scenarios based on the number of items would be:

2 Items (Minimum)

<div class="grid">
  <div class="player">Player 1</div>
  <div class="player">Player 2</div>
</div>

2 Player Grid

3 Items

<div class="grid">
  <div class="player">Player 1</div>
  <div class="player">Player 2</div>
  <div class="player">Player 3</div>
</div>

3 Player Grid

4 Items

<div class="grid">
  <div class="player">Player 1</div>
  <div class="player">Player 2</div>
  <div class="player">Player 3</div>
  <div class="player">Player 4</div>
</div>

4 Player Grid

So far what I've tried is the following:

.grid {
  height: 100%;
  display: grid;
  grid-template-columns: repeat(2, minmax(150px, 2fr));
  grid-template-rows: repeat(2, minmax(150px, 2fr));
  border: blue 5px solid;
}

.player {
  border: red 5px solid;
  display: flex;
  justify-content: center;
  align-items: center;
}

Changing the number of columns/rows to autofit/autofill also does not produce the desired result, and instead simply takes up the full width regardless. I've attached a live example of what I've tried below:

https://codesandbox.io/s/misty-smoke-bwvtt


Solution

  • Since it's only about 4 elements in total you can handle each case manually. In this situation, you only need two declarations without the need of any template. The implicit grid will do the job for you.

    .grid {
      display: grid;
      height: 300px;
      border: blue 5px solid;
    }
    
    .player {
      border: red 5px solid;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    
    /* 3 players: make the last one take two colums*/
    .player:nth-child(3):last-child {
      grid-column: span 2;
    }
    
    
    /* 4 players: make the fourth element in the second column */
    .player:nth-child(4) {
      grid-column: 2;
    }
    <div class="grid">
      <div class="player">Player 1</div>
      <div class="player">Player 2</div>
    </div>
    
    <div class="grid">
      <div class="player">Player 1</div>
      <div class="player">Player 2</div>
      <div class="player">Player 3</div>
    </div>
    
    <div class="grid">
      <div class="player">Player 1</div>
      <div class="player">Player 2</div>
      <div class="player">Player 3</div>
      <div class="player">Player 4</div>
    </div>

    For a 3x2 grid you can add more declaration:

    .grid {
      display: grid;
      height: 300px;
      border: blue 5px solid;
    }
    
    .player {
      border: red 5px solid;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    
    /* 3 players */
    .player:nth-child(3):last-child {
      grid-column: span 2;
    }
    
    
    /* 4 players  */
    .player:nth-child(4):last-child {
      grid-column: 2;
    }
    
    
    /* 5 players */
    .player:nth-child(1):nth-last-child(5),
    .player:nth-child(2):nth-last-child(4),
    .player:nth-child(3):nth-last-child(3) {
      grid-column: span 2;
    }
    
    .player:nth-child(4):nth-last-child(2) {
      grid-column: span 3;
    }
    
    .player:nth-child(5):nth-last-child(1) {
      grid-column:  4/span 3;
    }
    
    
    /* 6 players */
    .player:nth-child(6) {
      grid-column: 3;
    }
    <div class="grid">
      <div class="player">Player 1</div>
      <div class="player">Player 2</div>
    </div>
    
    <div class="grid">
      <div class="player">Player 1</div>
      <div class="player">Player 2</div>
      <div class="player">Player 3</div>
    </div>
    
    <div class="grid">
      <div class="player">Player 1</div>
      <div class="player">Player 2</div>
      <div class="player">Player 3</div>
      <div class="player">Player 4</div>
    </div>
    
    <div class="grid">
      <div class="player">Player 1</div>
      <div class="player">Player 2</div>
      <div class="player">Player 3</div>
      <div class="player">Player 4</div>
      <div class="player">Player 5</div>
    </div>
    
    <div class="grid">
      <div class="player">Player 1</div>
      <div class="player">Player 2</div>
      <div class="player">Player 3</div>
      <div class="player">Player 4</div>
      <div class="player">Player 5</div>
      <div class="player">Player 6</div>
    </div>