skip to Main Content

I am trying to make the CSS grid automatically size the final set of elements such that they autofill the last row if the amount of entries does not match the column count.

See image:

enter image description here

3

Answers


  1. You can do so by selecting the last odd child and providing grid-column: 1 / -1.

    .grid {
      border: 2.5px solid gray;
      border-radius: 10px;
      width: fit-content;
      height: fit-content;
      padding: 1em;
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 1em;
    }
    
    .grid__item {
      min-width: 100px;
      min-height: 100px;
      border: 2.5px solid palevioletred;
      text-align: center;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .grid__item:nth-child(2n-1):last-child {
      background: pink;
      grid-column: 1 / -1;
    }
    <div class="grid">
      <div class="grid__item">1</div>
      <div class="grid__item">2</div>
      <div class="grid__item">3</div>
      <div class="grid__item">4</div>
      <div class="grid__item">5</div>
      <div class="grid__item">6</div>
      <div class="grid__item">7</div>
    </div>
    Login or Signup to reply.
  2. You need display: flex and a bit of math.

    First, create a container element and its items:

    <div id="grid">
      <div class="item">
        <!-- ... -->
      </div>
      <!-- ...and more. -->
    </div>
    

    Then, make it a flexbox with flex-wrap: wrap:

    #grid {
      display: flex;
      flex-wrap: wrap;
    }
    

    Let the number of column we want be c. By observation we know that there are c columns (by definition), c - 1 gaps and 2 paddings, which sum up to 100% of the container’s width:

    ┌──────────────────────────┐
    │ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │
    │p│c1│g│c2│g│c3│g│c4│g│c5│p│
    │ └──┘ └──┘ └──┘ └──┘ └──┘ │
    │                          │
    │                          │
    │                          │
    │                          │
    └──────────────────────────┘
    

    This means an item’s width can be calculated as:

    w = (100% - (g * (c - 1)) - p * 2) / c
    

    We translate that to CSS accordingly, and add flex-grow: 1 to make the last items take all remaining spaces:

    .item {
      flex-grow: 1;
      width: calc((100% - var(--gap) * (var(--columns) - 1) - var(--padding) * 2) / var(--columns));
    }
    

    Try it:

    const grid = document.querySelector('#grid');
    const input = document.querySelector('input');
    
    input.addEventListener('input', function() {
      grid.style.setProperty('--columns', this.value);
    });
    
    const l = 30 + Math.random() * 71 | 0;
    
    for (let i = 1; i < l; i++) {
      const item = document.createElement('div');
      item.classList.add('item');
      item.textContent = i;
      grid.appendChild(item);
    }
    #grid {
      --columns: 3;
      --padding: 1em;
      --gap: 1em;
      
      display: flex;
      flex-flow: row wrap;
      gap: var(--gap);
      border: 1px solid #000;
      padding: var(--padding);
    }
    
    .item {
      flex-grow: 1;
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100px;
      width: calc(
        (
          100% -
          var(--gap) * (var(--columns) - 1) -
          var(--padding) * 2
        ) /
        var(--columns)
      );
      background: #ddd;
    }
    
    label {
      position: fixed;
      bottom: 2em;
      left: 2em;
    }
    <div id="grid"></div>
    
    <label>
      Columns:
      <input type="range" min="1" max="10" step="1" value="3">
    </label>
    Login or Signup to reply.
  3. Overall this is not a task for CSS-Grid but Flexbox. In Flexbox you can make use of flex-grow: 1 to make the elements grow to fill the remaining space.

    Flexbox can make use of flex-wrap: wrap so that elements that would overflow would break to the next row. The tricky part here is, that as such the width of every call must be calculated correctly.

    For the calculations, I recommend the usage of CSS variables. One variable for the gaps and then one variable for the columns. The correct width can be calculated by using that algorithm:

    width = ((100% - (size of gaps * (amount of columns - 1))) / amount of columns)

    To work correctly the containers box-model should be set to default (content-box) while the cards box model must be set to border-box so that the padding and border are included in the width:

    :root {
      --gap: 1em;
    }
    
    section {
      display: flex;
      flex-wrap: wrap;
      gap: var(--gap);
    }
    
    .col-2 {
      --column: 2;
    }
    
    .col-3 {
      --column: 3; 
    }
    
    section > div {
      flex-grow: 1;
      box-sizing: border-box;
      width: calc((100% - (var(--gap) * (var(--column) - 1))) / var(--column));
    }
    
    
    /* for demo purpose only */
    section > div {
      border: 2px dashed red;
      text-align: center;
      padding: 2em;
    }
    <h1>Grid with 2 columns and 3 cards</h1>
    <section class="col-2">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </section>
    
    <h1>Grid with 3 columns and 4 cards</h1>
    <section class="col-3">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
    </section>
    
    <h1>Grid with 3 columns and 5 cards</h1>
    <section class="col-3">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
    </section>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search