Someone else asked a similar question here but the answer only works if every element on the page is auto-placed and takes up only one column.
I have a 12-column grid layout in which the first three rows are all taken up by one element that spans all twelve columns; then I have three rows of auto-placed elements that each take up six columns.
While I could do the math to work this out based on that previous answer, it seems somewhat absurd to think that the calculated placement of the element isn't stored anywhere that is accessible by Javascript.
If I access the computed CSS properties regarding the grid, I'm just getting auto
and span 6
, rather than the actual computed number of row-start
or row-end
. Is there really no way to access the computed value of grid-row
and grid-column
?
I couldn’t find a way to retrieve grid coordinates directly.
Here’s a function that gets the grid coordinates of an element that’s inside a grid. It works for elements that take up more than 1 column or more than 1 row.
function getItemGridCoords(element) {
function digitsAndSpacesOnly(string) {
return string.replace(/[^\d\s.]/g, '');
}
function parseTemplate(gridTemplate) {
// parses a CSS grid-template-[row|column] to Numbers and does cumulative summation
// "100px 100px 100px" → [100,100,100] → [100,200,300]
return digitsAndSpacesOnly(gridTemplate).split(/\s/gmi).map(Number).reduce((array,currentValue) => {
array.push(currentValue + array[array.length-1]);
return array;
},[0]);
}
function findIndexOfClosest(array,target) {
return array.reduce((prev,curr,indexCurr) => {
return (Math.abs(curr - target) < Math.abs(array[prev] - target) ? indexCurr : prev);
});
}
const grid = element.parentElement;
const computedStyles = getComputedStyle(grid);
const getGapsAdder = gap => (n,i) => n + i * gap;
const colsPositions = parseTemplate(computedStyles['grid-template-columns']).map(getGapsAdder(digitsAndSpacesOnly(computedStyles['column-gap'])));
const rowsPositions = parseTemplate(computedStyles['grid-template-rows']).map(getGapsAdder(digitsAndSpacesOnly(computedStyles['row-gap'])));
const bounds = element.getBoundingClientRect();
const gridBounds = grid.getBoundingClientRect();
return {
col : findIndexOfClosest(colsPositions, bounds.left - gridBounds.left),
row : findIndexOfClosest(rowsPositions, bounds.top - gridBounds.top),
};
}
for (let element of document.querySelectorAll('.grid > *')) {
element.innerHTML = JSON.stringify(getItemGridCoords(element));
}
.grid {
font-family: monospace;
display: grid;
grid : auto-flow dense / repeat(12,1fr);
gap: 0.5em;
}
.grid > * {
white-space: nowrap;
background: aliceblue;
min-height: 2.5em;
}
.whole {
grid-column: auto / span 12;
}
.two-thirds {
grid-column: auto / span 8;
}
.half {
grid-column: auto / span 6;
}
.third {
grid-column: auto / span 4;
}
.skyscraper {
grid-row: auto / span 3;
}
<div class='grid'>
<span class='whole'></span>
<span class='half'></span>
<span class='half'></span>
<span class='half'></span>
<span class='half'></span>
<span class='half'></span>
<span class='half'></span>
</div>
<hr>
<div class='grid'>
<span class='third'></span>
<span class='third'></span>
<span class='third'></span>
<span class='half'></span>
<span class='half'></span>
<span class='half'></span>
<span class='half'></span>
</div>
<hr>
<div class='grid'>
<span class='third skyscraper'></span>
<span class='third'></span>
<span class='third'></span>
<span class='two-thirds'></span>
<span class='third'></span>
<span class='third'></span>
<span class='half'></span>
<span class='half'></span>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With