Search code examples
csscss-grid

How to place nested DIVs in a CSS grid with variable row heights?


I need to place 4 div containers in a 2 by 2 matrix. The width of the columns must be equal (and is therefore fixed), while the height of the rows must adapt itself to the content of the cells (and is therefore variable).

This is simple to do as long as the markup structure looks something like this:

<div class="wrapper">
  <div class="cell a1">...</div>
  <div class="cell a2">...</div>
  <div class="cell b1">...</div>
  <div class="cell b2">...</div>
</div>

The corresponding CSS would look like this:

.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

Unfortunately, my markup (which I cannot change easily) contains the cells in a nested markup structure:

<div class="wrapper">
  <div class="container">
    <div class="cell a1">...</div>
    <div class="cell a2">...</div>
  </div>
  <div class="container">
    <div class="cell b1">...</div>
    <div class="cell b2">...</div>
  </div>
</div>

As long as the height of the two rows can be equal, declaring .container as secondary grid solves the issue. But since the row height must be adjusted according to the cell content, this doesn't work.

Is there a way to place all four div.cell in the same grid defined by div.wrapper, although they are not direct child elements?


Solution

  • What you are looking for is Subgrid, feature currently (December 2021) only tested on Firefox Nightly.

    Info about this CSS attribute (from the Mozilla Web Docs page) :

    When you add display: grid to a grid container, only the direct children become grid items and can then be placed on the grid that you have created.

    You can "nest" grids by making a grid item a grid container. These grids however are independent of the parent grid and of each other, meaning that they do not take their track sizing from the parent grid. This makes it difficult to line nested grid items up with the main grid.

    For example, if you use grid-template-columns: subgrid and the nested grid spans three column tracks of the parent, the nested grid will have three column tracks of the same size as the parent grid.

    When the feature will be available and supported by multiple browsers this example below will work (I guess):

    html, body {
      width: 100%;
      height: 100%;
      margin: 0;
    }
    .wrapper {
      display: grid;
      height: 100vh;
      width: 100vw;
      background: grey;
      grid-auto-flow: rows;
      grid-template-columns: auto auto;
      grid-template-rows: auto auto;
    }
    .container {
      display: grid;
      grid-column: 1 / 3;
      grid-row: 1 / 3;
      grid-template-columns: subgrid;
      grid-template-rows: subgrid;
    }
    .a1{
      background-color: blue;
      grid-row: 1;
      grid-column: 1;
    }
    .a2{
      background-color: yellow;
      grid-row: 1;
      grid-column: 2;
    }
    .b1 {
      background-color: red;
      grid-row: 2;
      grid-column: 1;
    }
    .b2 {
      background-color: green;
      grid-row: 2;
      grid-column: 2;
    }
    <div class="wrapper">
      <div class="container a">
        <div class="cell a1">A1</div>
        <div class="cell a2">A2</div>
      </div>
      <div class="container a">
        <div class="cell b1">B1</div>
        <div class="cell b2">B2</div>
      </div>
    </div>

    And will render something like this : enter image description here