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.

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.