5

Trying to group items in two separate line by CSS Grid using different class names. It works fine until in "red" group have no more elements then predefined rows (this case 3).

Can I somehow put the 4th "red" element in new row?

If there is only 3 "red" element, everything works fine.

ul {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

.blue {
  background-color: blue;
}

.red {
  background-color: red;
  grid-row-start: 5;
}
<ul>
  <li class="blue">
    <h2>1</h2>
  </li>
  <li class="red">
    <h2>2</h2>
  </li>
  <li class="blue">
    <h2>3</h2>
  </li>
  <li class="blue">
    <h2>4</h2>
  </li>
  <li class="red">
    <h2>5</h2>
  </li>
  <li class="red">
    <h2>6</h2>
  </li>
  <!-- If you delete this (or any other "red") "li" element then it's working fine -->
  <li class="red">
    <h2>7</h2>
  </li>
  <li class="blue">
    <h2>8</h2>
  </li>
</ul>
Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
Arva Istvan
  • 53
  • 1
  • 4
  • I don't see how, the 4th column is there because it's part of the implicit grid. Once created it can't be ignored. – Paulie_D May 02 '19 at 17:16
  • Thank you! I searched now what is implicit grid. My problem is because of it. But how can I put my content from implicit grid to explicit? The "nth-child()" method is'nt good because "red" and "blue" elements order may vary. Can you suggest a different approach to this problem? – Arva Istvan May 02 '19 at 17:48

1 Answers1

9

You are specifying all the red elements into the fifth row by using grid-row-start: 5. Yes, the red elements are placed to the fifth row, and that is not immediately visible as you haven't specified an explicit row definition (say using grid-template-rows).


Implicit Rows

You can define the implicit row definition using something like grid-auto-rows: 50px and see that the red element are actually in the fifth row:

ul {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-auto-rows: 50px; /* specify row height */
  list-style: none; /* remove bullets */
  padding: 0; /* remove default ul padding */
}

.blue {
  background-color: blue;
}

.red {
  background-color: red;
  grid-row-start: 5;
}

li {
  border: 1px solid #bbb; /* border for illustration */
}
<ul>
  <li class="blue">
    <h2>1</h2>
  </li>
  <li class="red">
    <h2>2</h2>
  </li>
  <li class="blue">
    <h2>3</h2>
  </li>
  <li class="blue">
    <h2>4</h2>
  </li>
  <li class="red">
    <h2>5</h2>
  </li>
  <li class="red">
    <h2>6</h2>
  </li>
  <!-- If you delete this (or any other "red") "li" element then it's working fine -->
  <li class="red">
    <h2>7</h2>
  </li>
  <li class="blue">
    <h2>8</h2>
  </li>
</ul>

Implicit Columns

Now your question is why the fourth red item is in the same row - because you have placed all of them in the same fifth row. An implicit grid column is created with auto width - you can control this width using grid-auto-columns:

ul {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-auto-rows: 50px; /* specify row height */
  grid-auto-columns: 100px; /* specify column width */
  list-style: none; /* remove bullets */
  padding: 0; /* remove default ul padding */
}

.blue {
  background-color: blue;
}

.red {
  background-color: red;
  grid-row-start: 5;
}

li {
  border: 1px solid #bbb; /* border for illustration */
}
<ul>
  <li class="blue">
    <h2>1</h2>
  </li>
  <li class="red">
    <h2>2</h2>
  </li>
  <li class="blue">
    <h2>3</h2>
  </li>
  <li class="blue">
    <h2>4</h2>
  </li>
  <li class="red">
    <h2>5</h2>
  </li>
  <li class="red">
    <h2>6</h2>
  </li>
  <!-- If you delete this (or any other "red") "li" element then it's working fine -->
  <li class="red">
    <h2>7</h2>
  </li>
  <li class="blue">
    <h2>8</h2>
  </li>
</ul>

Solution

You can do this to group them:

  • set order: 1 to the red items so that they always come after the blue ones,

  • set the first red element to the first column using grid-column: 1 and the rest will be auto-placed using grid-column: auto.

See demo below:

ul {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  list-style: none; /* remove bullets */
  padding: 0; /* remove default ul padding */
}

.blue {
  background-color: blue;
}

.red {
  background-color: red;
  order: 1; /* red items have higher order */
}

.red { /* first red element into first column */
  grid-column: 1;
}

.red ~ .red { /* subsequent red elements auto-placed */
  grid-column: auto;
}

li {
  border: 1px solid #bbb; /* border for illustration */
}
<ul>
  <li class="blue">
    <h2>1</h2>
  </li>
  <li class="red">
    <h2>2</h2>
  </li>
  <li class="blue">
    <h2>3</h2>
  </li>
  <li class="blue">
    <h2>4</h2>
  </li>
  <li class="red">
    <h2>5</h2>
  </li>
  <li class="red">
    <h2>6</h2>
  </li>
  <!-- If you delete this (or any other "red") "li" element then it's working fine -->
  <li class="red">
    <h2>7</h2>
  </li>
  <li class="blue">
    <h2>8</h2>
  </li>
</ul>

Explicit vs Implicit Grid


Explicit grid

Explicit grid is the grid that you define using grid-template-columns, grid-template-rows, grid-template-areas and related shorthand properties - see excerpts below from W3C:

Explicit Grid (W3C)

The three properties grid-template-rows, grid-template-columns, and grid-template-areas together define the explicit grid of a grid container. The final grid may end up larger due to grid items placed outside the explicit grid; in this case implicit tracks will be created, these implicit tracks will be sized by the grid-auto-rows and grid-auto-columns properties.


See an example below of and explicit 2x2 grid which we will come back to shortly:

.wrapper {
  display: grid;
  grid-template-columns: 100px 100px;
  grid-template-rows: 50px 50px;
  grid-gap: 5px;
}
/* styles */
.wrapper > div { border: 1px solid cadetblue; background: lightblue; display: flex; justify-content: center; align-items: center;}
<div class="wrapper">
  <div>1</div><div>2</div><div>3</div><div>4</div>
</div>

Implicit grid

If you have more content or elements inside the grid container but outside the explicit grid definition, then that is part of what is called as the implicit grid.

You control the size of your implicit grid using grid-auto-rows and grid-auto-columns properties.

Implicit Grid (W3C)

The grid-template-rows, grid-template-columns, and grid-template-areas properties define a fixed number of tracks that form the explicit grid. When grid items are positioned outside of these bounds, the grid container generates implicit grid tracks by adding implicit grid lines to the grid. These lines together with the explicit grid form the implicit grid. The grid-auto-rows and grid-auto-columns properties size these implicit grid tracks.


You can see implicit rows created if you have more grid items in the example above - these rows can be sized using grid-auto-rows property:

.wrapper {
  display: grid;
  grid-template-columns: 100px 100px;
  grid-template-rows: 50px 50px;
  grid-gap: 5px;
  grid-auto-rows: 25px; /* size of implicit rows */
}
/* styles */
.wrapper > div { border: 1px solid cadetblue; background: lightblue; display: flex; justify-content: center; align-items: center;}
<div class="wrapper">
  <div>1</div><div>2</div><div>3</div><div>4</div>
  <div>5</div><div>6</div><div>7</div><div>8</div>
</div>

To have a look at implicit columns created you can try placing some grid items beyond the second column - these rows can be sized using grid-auto-columns property. See how a new column is created and how the grid behaves:

.wrapper {
  display: grid;
  grid-template-columns: 100px 100px;
  grid-template-rows: 50px 50px;
  grid-gap: 5px;
  grid-auto-rows: 25px; /* size of implicit rows */
  grid-auto-columns: 25px; /* size of implicit columns */
}

div:nth-child(5), div:nth-child(6) {
  grid-column: 3; /* place in thrid column */
}

/* styles */
.wrapper > div { border: 1px solid cadetblue; background: lightblue; display: flex; justify-content: center; align-items: center;}
<div class="wrapper">
  <div>1</div><div>2</div><div>3</div><div>4</div>
  <div>5</div><div>6</div><div>7</div><div>8</div>
</div>
kukkuz
  • 41,512
  • 6
  • 59
  • 95