Search code examples
csscss-grid

Variable grid-gap makes padding of grid-parent invade grid-elements


If I set a variable value for grid-gap like 10% the padding-bottom of the parent (<div id="grid">) starts flowing inside the children (<div class="grid-item">). Why is that and how can I prevent this behavior?

Here is an minimal example:

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

#grid {
  padding-bottom: 100px;
  display: grid;
  grid-gap: 10%;
  grid-template-columns: 100px;
}

.grid-item img {
  width: 100%;
}
<div id="grid">
  <div class="grid-item"><img src="https://cdn.sstatic.net/Img/teams/overview/secure.png?v=03c691959884">
    <h3>Stack Overflow</h3>
  </div>
  <div class="grid-item"><img src="https://cdn.sstatic.net/Img/teams/overview/secure.png?v=03c691959884">
    <h3>Stack Overflow</h3>
  </div>
</div>

You can use the Dev-Tools to inspect the grid-parent (<div id="grid">) and look at the padding or see this screenshot to see the issue (padding (green) infringing on the space of the grid-elements (dashed boxes)):


Solution

  • Here's my guess, based on my knowledge of the cascade, percentage lengths and the grid sizing algorithm. I haven't found anything official that specifically addresses this issue so, again, this is an extrapolation.

    For a percentage height to work, when there is no explicit height defined on the parent container, the browser first needs to render all other lengths. This way it arrives at the actual size of the container and can answer the question: "10% of what?".

    Hence, the browser first renders the items and the padding-bottom: 100px.

    Now it can calculate grid-gap: 10% or, more specifically, the row-gap: 10% component (a percentage height).

    Because all other sizes are already in place, this additional 10% height forces the lower item to intrude into the fixed padding space.

    In support of this theory, if we set a height on the container, which now provides a clear reference point for the percentage row height, the rule can be rendered in sequence with the others (i.e., there's no need for the percentage height to be rendered at the end), and the overlap is eliminated in most cases. (There will still be an overlap in shorter screens because the padding has a fixed height of 100px.)

    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    #grid {
      padding-bottom: 100px;
      display: grid;
      grid-gap: 10%;
      grid-template-columns: 100px;
      height: 100vh; /* new */
    }
    
    .grid-item img {
      width: 100%;
    }
    <div id="grid">
      <div class="grid-item"><img src="https://cdn.sstatic.net/Img/teams/overview/secure.png?v=03c691959884">
        <h3>Stack Overflow</h3>
      </div>
      <div class="grid-item"><img src="https://cdn.sstatic.net/Img/teams/overview/secure.png?v=03c691959884">
        <h3>Stack Overflow</h3>
      </div>
    </div>