Search code examples
csscss-grid

Can I make a CSS grid with dynamic number of rows or columns?


What I wanna do is to make a CSS grid with a dynamic number of cells. For the sake of simplicity, let's assume there will always be four cells per row. Can I specify a grid with such a dynamic number of rows?

To make it easier, here's the Flexbox implementation:

const COLORS = [
  '#FE9',
  '#9AF',
  '#F9A',
  "#AFA",
  "#FA7"
];

function addItem(container, template) {
  let color = COLORS[_.random(COLORS.length - 1)];
  let num = _.random(10000);
  
  container.append(Mustache.render(template, { color, num }));
}

$(() => {
  const tmpl = $('#item_template').html()
  const container = $('#app');
  
  for(let i=0; i<5; i++) { addItem(container, tmpl); }
  
  $('#add_el').click(() => {
    addItem(container, tmpl);
  })
  
  container.on('click', '.del_el', (e) => {
    $(e.target).closest('.item').remove();
  });
});
.container {
  width: 100%;
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-start;
}
.container .item {
  flex: 0 0 calc(25% - 1em);
  min-height: 120px;
  margin: 0.25em 0.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app" class="container">
</div>

<button id="add_el">Add element</button>

<template id="item_template">
  <div class="item" style="background: {{color}}">
    <p>{{ num }}</p>
    <p>
      <button class="del_el">Delete</button>
    </p>
  </div>
</template>

P.S. Apparently, I wasn't clear enough the first time... I want to recreate this effect using the latest CSS Grid Layout.


Solution

  • Okay, after reading the MDN reference, I found the answer! The key to dynamic rows (or columns) is the repeat property.

    const COLORS = [
      '#FE9',
      '#9AF',
      '#F9A',
      "#AFA",
      "#FA7"
    ];
    
    function addItem(container, template) {
      let color = COLORS[_.random(COLORS.length - 1)];
      let num = _.random(10000);
      
      container.append(Mustache.render(template, { color, num }));
    }
    
    $(() => {
      const tmpl = $('#item_template').html()
      const container = $('#app');
      
      for(let i=0; i<5; i++) { addItem(container, tmpl); }
      
      $('#add_el').click(() => {
        addItem(container, tmpl);
      })
      
      container.on('click', '.del_el', (e) => {
        $(e.target).closest('.item').remove();
      });
    });
    .container {
      width: 100%;
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      grid-template-rows: repeat(auto-fill, 120px);
      grid-row-gap: .5em;
      grid-column-gap: 1em;
    }
    
    .container .item {
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="app" class="container">
    </div>
    
    <button id="add_el">Add element</button>
    
    <template id="item_template">
      <div class="item" style="background: {{color}}">
        <p>{{ num }}</p>
        <p>
          <button class="del_el">Delete</button>
        </p>
      </div>
    </template>

    P.S. Or you can use grid-auto-rows in my particular example.