Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Count how many elements in dynamic row

When using CSS Grid Layout to dynamically arrange elements in rows the browser calculates how many items go in a row depending on the size of the viewport. I'm looking for a way using JavaScript to determine how many items are in each row at a given viewport size. My purpose is to fill the inevitable part empty row at the end.

For example, given the CSS and HTML listed below, and at a particular viewport size results in this layout:

CSS Grid Layout Narrow, Dynamic Rows, Part Empty Last Row

And at a wider viewport results in this layout:

CSS Grid Layout Wide, Dynamic Rows, Part Empty Last Row

Each have missing elements in the last row.

Having the maximum number of elements a row I can dynamically load more elements to fill in the last row so it's the same number as the rest.


Example CSS and HTML:

<style>

* {
  box-sizing: border-box;
}
body {
  padding: 1rem;
}

main {
  max-width: 500px;
  margin: 0 auto;
}
article {
  margin: 1rem 0;
  overflow: hidden;
}

main {
  max-width: 10000px;
  margin: 0;
}
article {
  margin: 0;
}
.listings {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 1rem;
}

.listings {
  font-family: Avenir, Roboto, Helvetica, san-serif;
  font-size: 80%;
}
.listing {
  display: flex;
  flex-flow: column;
  border: 1px solid silver;
}
.listing > h1 {
  margin: 1rem 1rem 0;
}
.listing > div {
  margin: 0.25em 1rem 1rem;
}
.listing > img {
  width: auto;
  max-height: 200px;
  order: -1;
  align-self: center;
}

</style>
<main class="listings">
    <article class="listing">
        <img src="images/computer.jpg">
        <h1>87,500</h1>
        <div>1008[3/2]0</div>
    </article>

    <article class="listing">
        <img src="images/computer.jpg">
        <h1>30,000</h1>
        <div>952[2/1]0</div>
    </article>

    <article class="listing">
        <img src="images/computer.jpg">
        <h1>70,000</h1>
        <div>1090[3/1]0</div>
    </article>

    <article class="listing">
        <img src="images/computer.jpg">
        <h1>11,000</h1>
        <div>828[2/1]2</div>
    </article>

    <article class="listing">
        <img src="images/computer.jpg">
        <h1>25,000</h1>
        <div>1484[2/1]0</div>
    </article>

    <article class="listing">
        <img src="images/computer.jpg">
        <h1>199,000</h1>
        <div>2160[3/2]0</div>
    </article>

    <article class="listing">
        <img src="images/computer.jpg">
        <h1>42,000</h1>
        <div>1509[3/2]0</div>
    </article>

    <article class="listing">
        <img src="images/computer.jpg">
        <h1>230,000</h1>
        <div>1885[3/2]0</div>
    </article>
</main>
like image 372
bloodyKnuckles Avatar asked Nov 16 '25 13:11

bloodyKnuckles


1 Answers

elem.getBoundingClientRect().left

The elem.getBoundingClientRect().left property can be used to get the number of dynamic rows in a CSS grid layout. Just loop through the article elements NodeList and compare the element's getBoundingClientRect().left value to the previous. The compared value will increase within each row then drop when starting in the next row. Count the increments until the first drop occurs to determine the number of elements in each row.

var articles = document.querySelectorAll('article')
console.log(articles[0].getBoundingClientRect().left) // 16
console.log(articles[1].getBoundingClientRect().left) // 238.156
console.log(articles[2].getBoundingClientRect().left) // 460.312
console.log(articles[3].getBoundingClientRect().left) // 682.468
console.log(articles[4].getBoundingClientRect().left) // 904.625
console.log(articles[5].getBoundingClientRect().left) // 1126.78
console.log(articles[6].getBoundingClientRect().left) // 16

Therefore we just need to count the increases in value between the previous left value and the next and once it drops we have our row count.


Here using call to apply array method reduce on the NodeList. Using reduce to carry forward the each value to compare to the next value:

var rowlen = Array.prototype.reduce.call(document.querySelectorAll('article'), function (prev, next) {
  if ( !prev[2] ) {
    var ret = next.getBoundingClientRect().left
    // if increasing, increment counter
    if ( !(prev[0] > -1 && ret < prev[1]) ) { prev[0]++ }
    else { prev[2] = 1 } // else stop counting
  }
  return [prev[0],ret, prev[2]] // [counter, elem, stop-counting]
}, [0,null,0])[0]

Codesandbox.io "complete partial row" example.

Or old-school JS, sporting a for loop nested in an IIFE:

var rowlen = (function () {
  for ( var ii = 0, arts = document.querySelectorAll('article'), 
        len = arts.length, el = 0, ell = 0; 
      ii < len; ii++ ) {
    el = arts[ii].getBoundingClientRect().left
    if ( el > ell || 0 === ell ) { ell = el }
    else { return ii; }
  }
}())

Codesandbox.io "drop partial row" example.

like image 191
bloodyKnuckles Avatar answered Nov 18 '25 21:11

bloodyKnuckles



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!