skip to Main Content

I’m really hoping that you can help me.
I have a for loop

  <ul>
  {% for product in collection.products  %}
     <li>{{product}}</li>
 {% endfor %}
 </ul>

I would like to create unequal rows:
first row – 2 products
second: 4
third 3
fourth: 2
fifth: 4
…..
And have something like this:

I’m trying to do this 2 month already. Could you please help me?

enter image description here

3

Answers


  1. So you want rows like

    00 01
    02 03 04 05
    06 07 08 
    

    You can use that schema to create css classes like this

    .col0, .col1{
      width: 50%;
    }
    .col2, .col3, .col4, .col5{
      width: 25%;
    }
    .col6, .col7, .col8{
      width: 33.3%;
    }
    

    And then in your code:

    {% for product in collection.products %}
        <li class="col{{ forloop.index0 | modulo : 9}}">{{product.title}}</li> 
    {% endfor %}
    

    Note that this will work for an arbitrary number of elements. The final html will look like this

    <ul>
    <li class="col0">x</li>
    <li class="col1">x</li>
    <li class="col2">x</li>
    <li class="col3">x</li>
    <li class="col4">x</li>
    <li class="col5">x</li>
    <li class="col6">x</li>
    <li class="col7">x</li>
    <li class="col8">x</li>
    <li class="col0">x</li>
    <li class="col1">x</li>
    <li class="col2">x</li>
    ...
    </ul>
    

    This is an example of the result.

    .col0, .col1{
      min-width: 50%;
    }
    .col2, .col3, .col4, .col5{
      min-width: 25%;
    }
    .col6, .col7, .col8{
      min-width: 33.3%;
    }
    ul{
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
      justify-content: space-between;
    }
    li{
      display: block;
      flex: 1;
    }
    
    
    li, just-for-better-display{
      background-color: #FAB100;
      border: 1px solid #0FAB10;
      margin: 5px -1px;
      padding: 5px 0;
      text-align: center;
    }
    <ul>
    <li class="col0">1</li>
    <li class="col1">2</li>
    <li class="col2">3</li>
    <li class="col3">4</li>
    <li class="col4">5</li>
    <li class="col5">6</li>
    <li class="col6">7</li>
    <li class="col7">8</li>
    <li class="col8">9</li>
    <li class="col0">10</li>
    <li class="col1">11</li>
    <li class="col2">12</li>
    <li class="col2">13</li>
    <li class="col2">14</li>
    </ul>

    Note that I’ve switched to min-width (and added flex: 1) to stretch the last elements to the maximum possible width.

    Login or Signup to reply.
  2. Not sure if you can do it with plain liquid itself without any tricks, but using js and css you will have a bit more freedom:

    <ul id="collection-grid">
      {% for product in collection.products  %}
        <li>{{product}}</li>
      {% endfor %}
    </ul>
    
    <style>
      ul#collection-grid {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
      }
      
      ul#collection-grid>li {
        display: block;
        background-color: yellow;
        margin: -1px;
        border: 1px solid black;
        text-align: center;
      }
      
      ul#collection-grid>li.col-6 {
        width: 50%
      }
      
      ul#collection-grid>li.col-3 {
        width: 25%
      }
      
      ul#collection-grid>li.col-4 {
        width: 33.3333%
      }
    
    </style>
    
    
    <script>
      document.addEventListener("DOMContentLoaded", function(event) {
        const chunkConfig = [{
          items: 2,
          className: "col-6"
        }, {
          items: 4,
          className: "col-3"
        }, {
          items: 3,
          className: "col-4"
        }];
        const listItems = document.querySelectorAll("#collection-grid > li");
        for (let i = 0, chunkIndex = 0, chunkItemsCount = 0; i < listItems.length; i++) {
          const chunk = chunkConfig[chunkIndex];
    
          listItems[i].classList.add(chunk.className);
    
          if (++chunkItemsCount === chunk.items) {
            chunkItemsCount = 0;
            if (chunkIndex === chunkConfig.length - 1) chunkIndex = 0;
            else chunkIndex++;
          }
        }
      });
    
    </script>
    

    Just modify css a little to make it fit your needs.

    UPD: I wrote this fiddle for tests purposes https://jsfiddle.net/4y8d1kvq/

    Login or Signup to reply.
    • Main logic I have used is I have filtered the index like keeping only index of selected two and skip next three and stored it in filteredProductIndexes. and than check weather it contains an index or not with filteredProductIndexes.includes(index).
    • filteredProductIndexes.includes(index) this will retunr true if index is there and false if not.
    • if above condition satisfied than I have added class .setHalf, which has css of flex:1 0 calc(50% - 30px);(it means two items before wraping).
    • and all the other product I have set css to flex:1 0 calc(33.33% - 30px); (this means three items before wrapping).
    • Talking about skipFilter(seq, pick, skip) pick is how many item we want to select and skip is how many items we want to skip and seq is an array of indexes.
    • I have found this function from this stackoverflow answer please visit that link for more information.
    • I am unsure why stackoverflow console is not loading but you can run this code in your project I have tested it on codepen and it works fine.
      Here is codepen screenshot
    function skipFilter(seq, pick, skip) {
      var stride = pick + skip;
    
      return seq.filter(function(_, i) {
        return i % stride < pick;
      });
    }
    
    const products = document.querySelectorAll(".product-container .product");
    let productIndexes = [];
    let pick = 2,
      skip = 3;
    products.forEach((product, index) => {
      productIndexes.push(index);
    })
    filteredProductIndexes =
      skipFilter(productIndexes, pick, skip);
    
    function skipFilter(seq, pick, skip) {
      var stride = pick + skip;
    
      return seq.filter(function(_, i) {
        return i % stride < pick;
      });
    }
    products.forEach((product, index) => {
      if (filteredProductIndexes.includes(index)) {
        product.classList.add("setHalf");
      }
    })
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    ul li {
      list-style-type: none;
    }
    
    .container {
      position: relative;
      max-width: 1200px;
      margin: 0 auto;
    }
    
    .product-container {
      display: flex;
      justify-content: space-between;
      gap: 15px;
      flex-wrap: wrap;
    }
    
    .product-container .product {
      flex: 1 0 calc(33.33% - 30px);
    }
    
    .product-container .product.setHalf {
      flex: 1 0 calc(50% - 30px);
    }
    
    .product-container .product img {
      height: 300px;
      width: 100%;
      object-fit: cover;
    }
    <div class="container">
      <ul class="product-container">
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
        <li class="product">
          <img src="https://source.unsplash.com/random">
        </li>
      </ul>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search