73

Why do I have an overflow on the X axis in the following snippet?

The overflow is generated once I apply grid-gap: 10px on my .body grid container.

div:not(.header):not(.body):not(.row) {
  border: 1px solid grey;
}

.header {
  margin-top: 20px;
  display: grid;
  grid-gap: 10px;
  grid-template-areas: "header-left header-right-up" "header-left header-right-down";
  grid-template-rows: 40px 40px;
  grid-template-columns: minmax(50px, 200px) auto;
}

.header-left {
  grid-area: header-left;
}

.header-right-up {
  grid-area: header-right-up;
}

.header-right-down {
  grid-area: header-right-down;
}

.body {
  margin-top: 20px;
  display: grid;
  grid-template-columns: 25% 50% 25%;
  grid-auto-rows: 80px; 
  grid-gap: 10px;
}

.row-left {
}

.row-center {
}

.row-right {
}
<div class="header">
  <div class="header-left">image</div>
  <div class="header-right-up">content</div>
  <div class="header-right-down">long content</div>
</div>

<div class="body">
    <div class="row-left"></div>
    <div class="row-center"></div>
    <div class="row-right"></div>

    <div class="row-left"></div>
    <div class="row-center"></div>
    <div class="row-right"></div>

    <div class="row-left"></div>
    <div class="row-center"></div>
    <div class="row-right"></div>
  </div>
</div>

https://codepen.io/anon/pen/WdJExz?editors=1100

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Damiano Barbati
  • 3,356
  • 8
  • 39
  • 51

6 Answers6

125

Short Answer

Because the width of the columns plus the width of the gaps is greater than 100%.


Explanation

You have a 3-column grid container (.body):

grid-template-columns: 25% 50% 25%

The total width of those columns is 100%.

You're then adding gutters between the columns (and rows):

grid-gap: 10px

which is shorthand for:

grid-column-gap: 10px;
grid-row-gap: 10px;

So this becomes the width calculation:

25% + 50% + 25% + 10px + 10px

Hence,

100% + 20px > 100%, which results in an overflow condition

Note that the grid-*-gap properties apply only between grid items – never between items and the container. That's why we calculate two grid gaps, not four.

As a solution, instead of percentage units, try using fr units, which apply only to free space. This means that fr lengths are calculated after any grid-gap lengths are applied.

grid-template-columns: 1fr 2fr 1fr

div:not(.header):not(.body):not(.row) {
  border: 1px solid grey;
}

.header {
  margin-top: 20px;
  display: grid;
  grid-gap: 10px;
  grid-template-areas: "header-left header-right-up" "header-left header-right-down";
  grid-template-rows: 40px 40px;
  grid-template-columns: minmax(50px, 200px) auto;
}

.header-left {
  grid-area: header-left;
}

.header-right-up {
  grid-area: header-right-up;
}

.header-right-down {
  grid-area: header-right-down;
}

.body {
  margin-top: 20px;
  display: grid;
  grid-template-columns: 1fr 2fr 1fr; /* ADJUSTMENT */
  grid-auto-rows: 80px;
  grid-gap: 10px;
}

.row-left {}

.row-center {}

.row-right {}
<div class="header">
  <div class="header-left">image</div>
  <div class="header-right-up">content</div>
  <div class="header-right-down">long content</div>
</div>

<div class="body">
  <div class="row-left"></div>
  <div class="row-center"></div>
  <div class="row-right"></div>

  <div class="row-left"></div>
  <div class="row-center"></div>
  <div class="row-right"></div>

  <div class="row-left"></div>
  <div class="row-center"></div>
  <div class="row-right"></div>
</div>

revised codepen demo

More details here: The difference between percentage and fr units

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 6
    another important thing to mention is that using fr units will not always equate to having same size of cells e.g. 50% 50% may not always be half/half. it depends on the content that goes inside cells. To prevent overflow of content or cell to expand to fit content you have to use minmax(0, 1fr) trick. more here: https://css-irl.info/debugging-css-grid-part-2-what-the-fraction/ – CodeGems Aug 29 '19 at 02:23
  • 2
    FYI - they've just added `gap` and declared `grid-gap` is a 'shorthand' of `gap` in the WD of the spec. – TylerH Oct 18 '19 at 08:55
  • What if grid-gap causes overflow and I have fr units (never use %)? – DuchSuvaa Apr 14 '23 at 11:03
19

If you want to use percentages or some other unit, there is one more solution. The use of the minmax() function will allow the columns to shrink to fit the parent container and not cause overflow.

The solution would look like this:

grid-template-columns: minmax(auto, 25%) minmax(auto, 50%) minmax(auto, 25%);
gap: 10px;

More on the minmax() function here.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Valentin Genev
  • 320
  • 2
  • 8
  • 1
    This fixes overflow but it can result in different width columns, which is likely not desired. As @CodeGems states above, you want to use the minmax(0, 1fr) trick - https://stackoverflow.com/questions/48214281/why-does-grid-gap-cause-an-overflow/48214864#answer-70154764 – Sam Holguin Dec 11 '22 at 14:56
  • @SamHolguin, OP originally used percentages; ofc. percentages can be presented as fractions, e.g. 1fr, 2fr, 1fr. Here's a demo: https://jsfiddle.net/valgen/z2koh56g/4/ – Valentin Genev Dec 11 '22 at 18:38
1

If you have a fixed number of grid columns that should be the same width and use grid-gap, there's a way to do it:

display: grid;
grid-template-columns: repeat(4, calc(25% - 0.75em));
grid-gap: 1em;

In this case, each row would have 4 grid columns, and the total space occupied by grid-gap would be 3em. In order to distribute the overflowing space evenly, divide the space by the number of grid columns.

3em / 4 = 0.75em

This makes all the grid columns have the same width.

Codepen demo

1

Late reply but 100% worth it.

Summary from many resources.

  1. Usage with %

Grid columns calculated with % are not taking into accounts gutters (aka gaps). Therefore you need to add the pixels of the added gaps to the calculation. so totalGridWidth = SUM(...%) + gutters = ~100% + gutters

  1. Usage with fr

The previous issue does not happen (exception on number 3.) as it includes to calculate the free space as well with the gaps. so calculation is as follow: (free space - gutters) / 12 = 1fr therefore here you could get ratios as fractions instead of portions as percentages.

Or in other words with the Least Common Divisor (1fr = 25%):

grid-template-columns: 1fr 2fr 1fr;

  1. Usage with minmax(0,Xfr)

By default the browser layout engine uses to calculate Xfr this formula minmax(auto,Xfr) which relies on the minimum size of your items, and when any of those items or inner elements are expected to grow in size indefinitely with things like width:100% the auto parameter will make still case 2. to run sometimes with overflown grids. To prevent this, we need to force the browser to use a method that can shrink the elements until its real minimum, which is 0px to do this you need to use minmax(0,Xfr) with X as the desired fraction.

Or in other words, for your previous case:

grid-template-columns: minmax(0,1fr) minmax(0,2fr) minmax(0,1fr);

I know this might look too verbose, but given your such edge case we cannot use repeat() here, and in any case, this will be a bulletproof for your overflowing issues.

You can read more in this article I have found:

https://css-tricks.com/preventing-a-grid-blowout/

Ignacio Bustos
  • 1,415
  • 2
  • 17
  • 26
0

I stumbled into this problem too, and what it worked for me was to replace grid-template-column: 50% 50%; with grid-template-column: auto 50%;.

Luis Araujo
  • 91
  • 1
  • 4
0

In my case there was a problem in using percents: " gap: 2%; " This becomes to overflow. When I use "px" or other dimension instead of percents (%) - everythisng is ok.