0

I want to leverage CSS Grid to evenly size those elements which are part of the same CSS Grid axis:

[class*=' container-grid-'], [class^='container-grid-'] {
  /* give margin-bottom to all kinds of "container-grid-", see https://stackoverflow.com/a/13352103/923560 */
  margin-bottom: 2rem;
}

[class*=' container-grid-']  > .col, [class^='container-grid-'] > .col {
  display: contents;
}

.container-grid-2by2 {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(2, auto);
  row-gap: 0;
  column-gap: 1rem;
}


.container-grid-3by3 {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, auto);
  row-gap: 0;
  column-gap: 1rem;
}

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.blue {
 background-color: skyblue;
}

.limit-width {
  max-width: 20rem;
  background-color: silver;
}
<div class="limit-width">

<h1><code>.container-grid-2by2</code></h1>

<div class="container-grid-2by2">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid-3by3</code></h1>

<div class="container-grid-3by3">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz3
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3 Bar3 Bar3 Bar3 Bar3 
    </div>
    <div class="blue">
      Baz3
    </div>
  </div>
</div>

</div>

As you can see, elements on the same CSS grid row axis receive the same height, e.g. a cell with little text content (Foo1) stretches to match the height of the cell with most text content (Foo2 Foo2 Foo2 ...). Awesome, that's exactly what I want!

HTML follows the following structure: a <div class="container-grid-*"> element acting as the CSS grid container; inside it several <div class="col"> acting as columns; and then inside those columns the actual content HTML elements. The .col elements use display: contents; to "delegate" CSS grid cell determination to the actual content HTML elements.

But right now, my CSS requires explicit rules for each column and row count: .container-grid-2by2, .container-grid-3by3, .container-grid-2by3, .container-grid-3by2, etc.

There should be a way to refactor this, no?

Is there any CSS trick to automatically derive CSS grid column and row counts?

For my circumstances, it can always be assumed that within a container, each column has the same amount of actual HTML content elements; e.g. within a container all columns will have x elements.

Abdull
  • 26,371
  • 26
  • 130
  • 172

1 Answers1

0

I found two solutions which haven't gone the full way of generalization, and rely on workaround and hacks.

Not-so-hacky solution

Successfully tested in Chrome 96 and Firefox 94.

This solution relies on a "pre-calculated" set of CSS rules, putting the nth-child(x) .col child into the x's grid-row. As the .container-grid is defines a completely implicit (versus explicit) CSS grid, the next .col's first element will automatically introduce the next column and be placed in that next column.

.container-grid {
  display: grid;
  row-gap: 0;
  column-gap: 1rem;
  grid-auto-columns: 1fr;
}

.container-grid > .col {
  display: contents;
}


.container-grid > .col > div:nth-child(1) {
  grid-row: 1;
}

.container-grid > .col > div:nth-child(2) {
  grid-row: 2;
}

.container-grid > .col > div:nth-child(3) {
  grid-row: 3;
}

.container-grid > .col > div:nth-child(4) {
  grid-row: 4;
}

/* ... and so on up to the maximum amount of vertical grid elements you can imagine in each row */

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.blue {
  background-color: skyblue;
}

.yellow {
  background-color: yellow;
}

.limit-width {
  max-width: 30rem;
  background-color: silver;
}
<div class="limit-width">

<h1><code>.container-grid</code> 1col x 1row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
  </div>
</div>

</div>



<div class="limit-width">

<h1><code>.container-grid</code> 1col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 1row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 3col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3 
    </div>
  </div>
</div>

</div>



<div class="limit-width">

<h1><code>.container-grid</code> 3col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 4col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo4 
    </div>
    <div class="green">
      Bar4
    </div>
    <div class="blue">
      Baz4 
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 4col x 4row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
    <div class="yellow">
      Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
    <div class="yellow">
      Qux2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
    <div class="yellow">
      Qux3 Qux3 Qux3 Qux3 
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo4 
    </div>
    <div class="green">
      Bar4
    </div>
    <div class="blue">
      Baz4 
    </div>
    <div class="yellow">
      Qux4
    </div>
  </div>
</div>

</div>

Awfully hacky solution

Successfully tested in Chrome 96 and Firefox 94.

This solution relies on a ::after pseudo-element for each .col: this pseudo-element occupies/hacks in enough extra grid-row to overflow into a next implicit column. The 0 in grid-auto-columns: 1fr 0; makes sure that this phantom column occupies no horizontal space.

This solution relies on the hack to give an explicitly high value for the pseudo-element grid-row value.

.container-grid {
  display: grid;
  row-gap: 0;
  column-gap: 0.5rem; /* column-gap is created for both .col and pseudo-element phantom column, therefore to achieve an effective column-gap of 1rem, we use the half value of 0.5rem */
  grid-auto-flow: column;
  grid-auto-columns: 1fr 0; /* 1fr is for each .col, 0 is for its follow-up pseudo-element phantom column to occupy no horizontal space */ 
}

.container-grid > .col {
  display: contents;
}

.container-grid > .col::after {
  content: "";
  grid-row: span 8; /* span x, where x is the maximum amount of elements that will every be in a column */
  background-color: pink;
}

.container-grid > .col:only-child::after {
  /* ugly fix for the case of 1col x 1row and 1col x 2row */
  grid-row: 9; /* y, where y = x + 1, where x is the maximum amount of elements that will every be in a column */
}

.container-grid > .col:not(:first-child):last-child::after {
  /* last .col shall not create a follow-up pseudo-element phantom column
  content: unset; 
}

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.blue {
  background-color: skyblue;
}

.yellow {
  background-color: yellow;
}

.limit-width {
  max-width: 30rem;
  background-color: silver;
}
<div class="limit-width">

<h1><code>.container-grid</code> 1col x 1row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
  </div>
</div>

</div>



<div class="limit-width">

<h1><code>.container-grid</code> 1col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 1row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 2col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 3col x 2row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3 
    </div>
  </div>
</div>

</div>



<div class="limit-width">

<h1><code>.container-grid</code> 3col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 4col x 3row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo4 
    </div>
    <div class="green">
      Bar4
    </div>
    <div class="blue">
      Baz4 
    </div>
  </div>
</div>

</div>


<div class="limit-width">

<h1><code>.container-grid</code> 4col x 4row</h1>

<div class="container-grid">
  <div class="col">
    <div class="red">
      Foo1
    </div>
    <div class="green">
      Bar1
    </div>
    <div class="blue">
      Baz1
    </div>
    <div class="yellow">
      Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1 Qux1
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2 Foo2
    </div>
    <div class="green">
      Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2 Bar2
    </div>
    <div class="blue">
      Baz2
    </div>
    <div class="yellow">
      Qux2
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 Foo3 
    </div>
    <div class="green">
      Bar3 Bar3 Bar3 Bar3
    </div>
    <div class="blue">
      Baz3 
    </div>
    <div class="yellow">
      Qux3 Qux3 Qux3 Qux3 
    </div>
  </div>
  <div class="col">
    <div class="red">
      Foo4 
    </div>
    <div class="green">
      Bar4
    </div>
    <div class="blue">
      Baz4 
    </div>
    <div class="yellow">
      Qux4
    </div>
  </div>
</div>

</div>

UPDATE: It seems that the awfully hacky solution doesn't work via Run code snippet, but it works in the Code Snippet Editor.

Abdull
  • 26,371
  • 26
  • 130
  • 172