Search code examples
htmlcsscss-grid

Using CSS GRID Why Im getting this gap?


Im learning CSS GRID and I dont know why Im getting a gap in the following example. The second item could fit in the first track but instead Im getting a gap there. Here is the code:

.container {
  display: grid;
  margin: 40px;
  grid-gap: 20px;
  text-align: center;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
}

.container div {
  background: #ff8000;
}

.container .item1 {
  grid-column: 2/4;
}
<div class="container">
  <div class="item1">1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
  <div>9</div>
  <div>10</div>
  <div>11</div>
  <div>12</div>
</div>

Now if I add the following property grid-row: 1/2; to the first item, now the second item occupies the first track. That is what I expect. Here is the code adding grid-row: 1/2;:

.container {
  display: grid;
  margin: 40px;
  grid-gap: 20px;
  text-align: center;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
}

.container div {
  background: #ff8000;
}

.container .item1 {
  grid-column: 2/4;
  grid-row: 1/2;
}
<div class="container">
  <div class="item1">1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
  <div>9</div>
  <div>10</div>
  <div>11</div>
  <div>12</div>
</div>

My question is:

Why in the first code Im getting a gap? The second item can fit in the first track.

And what is the difference between the first and the second code that I have written?


Solution

  • You need to understand the placement algorithm to understand this behavior. From the specification you can find the full algorithm and how to identify when each item will be treated which is the key here to understand the difference between both cases.

    The main steps of the algorithm are:

    1. Generate anonymous grid items

    2. Position anything that’s not auto-positioned.

    3. Process the items locked to a given row.

    4. Determine the columns in the implicit grid.

    5. Position the remaining grid items.

    Let's start with your last example where you explicitely defined a grid-colum and grid-row for the first item which make it a not auto-positioned element so we place it at the step (1).

    Then we will go to step (4) to position the remaining items

    The auto-placement cursor defines the current “insertion point” in the grid, specified as a pair of row and column grid lines. Initially the auto-placement cursor is set to the start-most row and column lines in the implicit grid.

    So our cursor is the top/left cell and the item2 will be placed there and we simply follow the tree order to place all the other element:

    For each grid item that hasn’t been positioned by the previous steps, in order-modified document order:

    Of course, no item will overlap the item1 already placed and we keep incrementing the cursor for each item following the algorithm.


    Now let's consider the first tricky case where the only difference is that you didn't specify the grid-row and this will no more make your element a not auto-positioned one because you only defined the grid-column so the row will be automatically defined and the item will now fall into the step (4) and if you check closely the step (4) you will find two sub steps:

    If the item has a definite column position:

    If the item has an automatic grid position in both axes:

    The item1 will consider the first one, will get placed in the second column and will increment the cursor!. The incrementation of the cursor is what make the second element placed after.

    In your second example the item1 will not use the cursor since it's considered in the step (1) so the item2 will be the first to use the cursor unlike in your first example where item1 will be the first one to use it.

    Worth to note that in the step (4) we have two kind of algorthim. The "sparse" one (the default behavior) where we never reset the cursor and we always increment it which create gaps. The "dense" algorithm that reset the cursor at each step in order to fill all the cells. To activate the "dense" algorithm you need to consider grid-auto-flow

    .container {
      display: grid;
      margin: 40px;
      grid-gap: 20px;
      text-align: center;
      grid-template-columns: repeat(4, 1fr);
      grid-template-rows: repeat(4, 1fr);
      grid-auto-flow: dense;
    }
    
    .container div {
      background: #ff8000;
    }
    
    .container .item1 {
      grid-column: 2/4;
    }
    <div class="container">
      <div class="item1">1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
      <div>7</div>
      <div>8</div>
      <div>9</div>
      <div>10</div>
      <div>11</div>
      <div>12</div>
    </div>

    dense

    If specified, the auto-placement algorithm uses a “dense” packing algorithm, which attempts to fill in holes earlier in the grid if smaller items come up later. This may cause items to appear out-of-order, when doing so would fill in holes left by larger items.

    If omitted, a “sparse” algorithm is used, where the placement algorithm only ever moves “forward” in the grid when placing items, never backtracking to fill holes. This ensures that all of the auto-placed items appear “in order”, even if this leaves holes that could have been filled by later item ref


    Related question with another non-intuitive behavior explained with the same algorithm: CSS Grid : How Auto placement algorithm works