Search code examples
cssgrid-layout

Grid layout with auto columns resize with a full-width flex child


I have created a table with expandable rows using CSS Grid Layout and everything works fine until I add an element with a flex layout in the expandable section.

The expandable section use a grid-column: 1/-1; and the content should not affect the rest of the grid or that is what i thought.

I have created a simplified version to show the problem:

function toggle() {
  const elem = document.querySelector('.all-columns');
  if (elem.style.display === "none") {
    elem.style.display = "flex";
  } else {
    elem.style.display = "none";
  }
}
.grid-container {
  display: grid;
  grid-template-columns: auto auto auto;
  width: 400px;
}

.row {
  display: contents;
}

.all-columns {
  grid-column: 1/-1;
  display: flex;
  flex-wrap: wrap;
  background: red;
  border: 1px solid black;
}

.column {
  border: 1px solid black;
}

.flex-child {
  width: 180px;
  text-align: center;
  background: blue;
  border: 1px solid black;
}
<div class="grid-container">
  <div class="row">
    <div class="column">Row1 Column1</div>
    <div class="column">Row1 Column2 with large name</div>
    <div class="column">Row1 Column3</div>
  </div>
  <div class="row">
    <div class="all-columns">
      <div class="flex-child">1 flex</div>
      <div class="flex-child">2 flex</div>
      <div class="flex-child">3 flex</div>
      <div class="flex-child">4 flex</div>
      <div class="flex-child">5 flex</div>
    </div>
  </div>
  <div class="row">
    <div class="column">Row3 Column1</div>
    <div class="column">Row4 Column2</div>
    <div class="column">Row1 Column3</div>
  </div>
</div>
<br>
<button onclick="toggle()">Toggle expandable section</button>

As you can see, the size of the middle column changes when the expandable section is shown/hide.

The content of the expandable section is external so I cannot modify it at all. I have tested it in Firefox and Chrome with the same result.

I'd appreciate if someone has an explanation for this behaviour.

Thanks.


Solution

  • add width: 0;min-width: 100%; to all-columns so it won't contribute to defining the width and won't affect the other elements:

    function toggle() {
      const elem = document.querySelector('.all-columns');
      if (elem.style.display === "none") {
        elem.style.display = "flex";
      } else {
        elem.style.display = "none";
      }
    }
    .grid-container {
      display: grid;
      grid-template-columns: auto auto auto;
      width: 400px;
    }
    
    .row {
      display: contents;
    }
    
    .all-columns {
      grid-column: 1/-1;
      width: 0;
      min-width: 100%;
      display: flex;
      flex-wrap: wrap;
      background: red;
      border: 1px solid black;
    }
    
    .column {
      border: 1px solid black;
    }
    
    .flex-child {
      width: 180px;
      text-align: center;
      background: blue;
      border: 1px solid black;
    }
    <div class="grid-container">
      <div class="row">
        <div class="column">Row1 Column1</div>
        <div class="column">Row1 Column2 with large name</div>
        <div class="column">Row1 Column3</div>
      </div>
      <div class="row">
        <div class="all-columns">
          <div class="flex-child">1 flex</div>
          <div class="flex-child">2 flex</div>
          <div class="flex-child">3 flex</div>
          <div class="flex-child">4 flex</div>
          <div class="flex-child">5 flex</div>
        </div>
      </div>
      <div class="row">
        <div class="column">Row3 Column1</div>
        <div class="column">Row4 Column2</div>
        <div class="column">Row1 Column3</div>
      </div>
    </div>
    <br>
    <button onclick="toggle()">Toggle expandable section</button>