A way to count columns in a responsive grid
I think the easiest way without brute force is to consider a simple division. You can easily find the width of the container and each column is defined by minmax(300px,1fr)
and we know the gap
. Using all these information the calculation should be done like below:
If we will have N
columns then we will have N-1
gaps. We also know that W
should at least be 300px
and cannot be more than a value (we will call Wmax
).
Let's suppose the gap is equal to 10px
.
If N=2
and each column is equal to 300px
we will have the container width equal to 300px*2 + 10px*1 = 610px
.
If N=3
and each column is equal to 300px
we will have 300px*3 + 10px*2=920px
.
Now it's clear that if the container width is between 610px
and 920px
we will have 2 columns because there is no space to hold 3 columns but enough space to hold 2 columns that we expand to fill the remaining space (using 1fr
) so Wmax
in this case is (920px - 10px)/2 = 455px
. In other words, the width will vary from 300px
to 455px
when having 2 columns.
So if we take the formula 300px*N + 10px*(N-1) = Wc
with Wc
our container width you will see that N
is equal to 2
when Wc=610px
and 3
when Wc=920px
and between we will have a result in [2,3]
so we simply round the value to the smallest one (2 in this case) and we will have our column number.
Here is a basic example:
var gap = 10;
var minW = 200;
var Wc = document.querySelector('.grid').offsetWidth;
var N = Math.floor((Wc+gap)/(minW+gap));
console.log(N);
window.addEventListener('resize', function(event){
Wc = document.querySelector('.grid').offsetWidth;
N = Math.floor((Wc+gap)/(minW+gap));
console.log(N);
});
.grid {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(200px,1fr));
grid-gap:10px;
}
span {
min-height:50px;
background:red;
}
<div class="grid">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
In case you don't know the value of gap and min-width you can consider getComputedStyle()
to get the different values. In this case, the N
should already be an Integer because grid-template-columns
will give us the computed width of each column (in practice, we will still have some fraction due to rounding ).
var grid = document.querySelector('.grid');
var gap = parseFloat(window.getComputedStyle(grid,null).getPropertyValue("column-gap"));
var minW = parseFloat(window.getComputedStyle(grid,null).getPropertyValue("grid-template-columns"));
var Wc = document.querySelector('.grid').offsetWidth;
var N = (Wc+gap)/(minW+gap);
console.log(N);
window.addEventListener('resize', function(event){
Wc = document.querySelector('.grid').offsetWidth;minW = parseFloat(window.getComputedStyle(grid,null).getPropertyValue("grid-template-columns"))
N = (Wc+gap)/(minW+gap);
console.log(N);
});
.grid {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(200px,1fr));
grid-gap:10px;
}
span {
min-height:50px;
background:red;
}
<div class="grid">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
One way to get the number of rows/columns of a css grid is by using the grid-template-rows
or grid-template-columns
from the computed style of the grid window.getComputedStyle(grid)
.
The returned values are always transformed to separated pixel values (e.g. 20px 20px 50px), where each value represents the size of the respective column/row. All that's left to do is splitting up the string into an array and counting the number of values.
const gridComputedStyle = window.getComputedStyle(grid);
// get number of grid rows
const gridRowCount = gridComputedStyle.getPropertyValue("grid-template-rows").split(" ").length;
// get number of grid columns
const gridColumnCount = gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").length;
console.log(gridRowCount, gridColumnCount);
Here is the full snippet (Codepen):
function getGridData () {
// calc computed style
const gridComputedStyle = window.getComputedStyle(grid);
return {
// get number of grid rows
gridRowCount: gridComputedStyle.getPropertyValue("grid-template-rows").split(" ").length,
// get number of grid columns
gridColumnCount: gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").length,
// get grid row sizes
gridRowSizes: gridComputedStyle.getPropertyValue("grid-template-rows").split(" ").map(parseFloat),
// get grid column sizes
gridColumnSizes: gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").map(parseFloat)
}
}
window.addEventListener("DOMContentLoaded", outputGridData);
window.addEventListener("resize", outputGridData);
function outputGridData () {
const gridData = getGridData();
output.textContent = `
Rows: ${gridData.gridRowCount}
Columns: ${gridData.gridColumnCount}
Rows sizes: ${gridData.gridRowSizes}
Column sizes: ${gridData.gridColumnSizes}
`;
}
#grid {
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(auto-fill, 200px);
}
#output {
white-space: pre-wrap;
}
.A, .B, .C {
font-family: Arial;
font-weight: 600;
font-size: 2rem;
border-radius: 50% 50%;
width: 80px;
height: 80px;
text-align: center;
line-height: 80px;
box-shadow: -3px 5px 20px -3px #AAA;
border: solid 10px #fff;
color: #fff;
}
.A {
background: #ffc300;
}
.B {
background: #c70039;
}
.C {
background: #581845;
}
<div id="output"></div>
<div id="grid">
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
</div>