box.addEventListener("click", () => box" /> box.addEventListener("click", () => box" /> box.addEventListener("click", () => box"/>

css grid, collapse a cell, ho to make then one in next row rise up

1.1k Views Asked by At

I have made this simple example of my current grid setup:

document.querySelectorAll(".element").forEach(box => 
    box.addEventListener("click", () => box.classList.toggle("compressed"))
)
.container{
  display:grid;
  grid-template-columns: repeat(3, min-content);
  grid-template-rows:repeat(3, min-content);
  grid-auto-flow:column;
  gap:1rem;
}

.element{
  background-color:brown;
  border:1px solid black;
  width:10rem;
  height:10rem;
  text-align:center;
  color:white;
  line-height:10rem;
  font-size:2rem;
}

.elementBig{
  grid-row-end: span 2;
   height:21rem;
}

.compressed{
  height:2rem;
}
<div class="container">
<div class="element elementBig">big</div>
<div class="element">1</div>
<div class="element">2</div>
<div class="element">3</div>
<div class="element">4</div>
<div class="element">5</div>
<div class="element">6</div>
<div class="element">7</div>
<div class="element">8</div>
<div class="element">9</div>
<div class="element">10</div>
</div>

when you click on a cell it's reduced but the next one does not rise up: let's say I click on "big" element, I want that "1" to rise up

in addiction i want rows and columns number to be dynamic so in the real grid i'am using this setup:

--n-colonne: 3; //per impostare massimo numero di colonne a 3 su grandi display
    display: grid;
    $larghezza-senza-spazi: calc(100% - (var(--n-colonne) - 1) * 1rem);
    grid-template-columns: repeat(auto-fill, minmax(max(45rem, ($larghezza-senza-spazi)/var(--n-colonne)), 1fr));
    grid-template-rows: repeat(12, min-content);
    grid-gap: 1rem;

that will need some fix if "grid-auto-flow:column" is to be used

1

There are 1 best solutions below

3
rx2347 On

The problem you're facing: A grid has rows and rows have a certain height (in your case: min-content, which is 10rem as long as at least one box in the row is not compressed). In addition to that, your big box is supposed to always take up two rows as per your definition (grid-row-end: span 2;), so resizing the content of the grid-cell won't change anything.

Not sure if grid is the way to go here, there might be a solution in the new masonry addition in CSS3. Maybe give this a read: https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/

However: If you can settle on a number of cols (or calculate this somehow by using js), just place your boxes accordingly in cols and it works just fine.

document.querySelectorAll(".element").forEach(box =>
  box.addEventListener("click", () => box.classList.toggle("compressed"))
)
.container {
  display: grid;
  grid-template-columns: repeat(3, min-content);
  grid-auto-flow: column;
  gap: 1em;
}

.element {
  background-color: brown;
  border: 1px solid black;
  width: 10rem;
  height: 10rem;
  text-align: center;
  color: white;
  line-height: 10rem;
  font-size: 2rem;
  margin-bottom: 0.5em;
}

.elementBig {
  grid-row-end: span 2;
  height: 21rem;
}

.compressed {
  height: 2rem;
  overflow: hidden;
}
<div class="container">
  <div class="col1">
    <div class="element elementBig">big</div>
    <div class="element">1</div>
  </div>
  <div class="col2">
    <div class="element">2</div>
    <div class="element">3</div>
    <div class="element">4</div>
  </div>

  <div class="col3">
    <div class="element">5</div>
    <div class="element">6</div>
    <div class="element">7</div>
  </div>

  <div class="col4">
    <div class="element">8</div>
    <div class="element">9</div>
    <div class="element">10</div>
  </div>
</div>

If thats not an option, you can always use flexbox, but it comes with its own challenges:

document.querySelectorAll(".element").forEach(box =>
  box.addEventListener("click", () => box.classList.toggle("compressed"))
)
.container {
  display: flex;
  flex-flow: column wrap;
  width: 100%;
  max-height: 800px;
  gap: 1rem;
}

.element {
  background-color: brown;
  border: 1px solid black;
  width: 200px;
  height: 200px;
  text-align: center;
  color: white;
  line-height: 10rem;
  font-size: 2rem;
}

.elementBig {
  height: 21rem;
}

.compressed {
  height: 2rem;
}
<div class="container">
  <div class="element elementBig">big</div>
  <div class="element">1</div>
  <div class="element">2</div>
  <div class="element">3</div>
  <div class="element">4</div>
  <div class="element">5</div>
  <div class="element">6</div>
  <div class="element">7</div>
  <div class="element">8</div>
  <div class="element">9</div>
  <div class="element">10</div>
</div>