Is there a way to directly access the actual grid coordinates of an auto-placed element in CSS grid?
Asked Answered
M

1

17

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?

Mealy answered 11/3, 2019 at 19:12 Comment(7)
Is there some reason Element.getBoundingClientRect() doesn't do the job? developer.mozilla.org/en-US/docs/Web/API/Element/…Henchman
@RandyCasburn My understanding is that it returns values in pixels, whereas I want the value in terms of rows and columns. My goal in this particular case is to determine which row a clicked element is on at the time of the click, so I can adjust its size without changing its row.Mealy
Forgive the confusion here, but grid-row and grid-column are definitive. You defined them: 12-column 3-row, 6-column 1-row. These don't change. 1fr, 2fr, 3fr all are consistent measurements regardless of viewport size. So since all these column/row definitions are fixed, the only thing that changes is the pixel mesures of each of the block level elements. Regardless of size, a 6-column 1-row element will always be a 6-column 1-row element. Help me become unconfused.Henchman
Ah, sorry, I'm not being clear-- I've defined the size of the grid, but not the position of all of the elements in the grid. The elements are always 6-column, 1-row, but the row that they're in (and the column that they begin in) is not explicitly assigned by me. I want to figure out which row they've been assigned to by the auto-placement algorithm.Mealy
Went back and re-read the spec. It doesn't appear there is a non-computational solution for your use case.Henchman
Could you post the source html and css?Zakaria
Possible duplicate of #61964780Nikolos
N
2

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>
Nikolos answered 22/3, 2022 at 5:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.