By Morpheus


2017-07-13 20:54:51 8 Comments

I am playing around with CSS Grid Layout and came across a question I cannot find an answer for.

Consider the following example:

:root {
  --grid-columns: 12;
  --column-gap: 10px;
  --row-gap: 10px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), calc(100% / var(--grid-columns)));
  grid-column-gap: var(--column-gap);
  grid-row-gap: var(--row-gap);
  justify-content: center;		
} 

[class*=l-] {
  border: 1px solid red;
}

.l-1 {
  grid-column-start: span 1;		
}

.l-2 {
  grid-column-start: span 2;
}

.l-3 {
  grid-column-start: span 3;
}

.l-4 {
  grid-column-start: span 4;
}

.l-5 {
  grid-column-start: span 5;
}

.l-6 {
  grid-column-start: span 6;
}

.l-7 {
  grid-column-start: span 7;
}

.l-8 {
  grid-column-start: span 8;
}

.l-9 {
  grid-column-start: span 9;
}

.l-10 {
  grid-column-start: span 10;
}

.l-11 {
  grid-column-start: span 11;
}

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

As you can see the columns go out of the screen width because of the percentage width set with calc(100% / var(--grid-columns)).

But if I use fr units, it works perfectly:

:root {
  --grid-columns: 12;
  --column-gap: 10px;
  --row-gap: 10px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr); 
  grid-column-gap: var(--column-gap);
  grid-row-gap: var(--row-gap);
  justify-content: center;		
}

[class*=l-] {
  border: 1px solid red;
}

.l-1 {
  grid-column-start: span 1;		
}

.l-2 {
  grid-column-start: span 2;
}

.l-3 {
  grid-column-start: span 3;
}

.l-4 {
  grid-column-start: span 4;
}

.l-5 {
  grid-column-start: span 5;
}

.l-6 {
  grid-column-start: span 6;
}

.l-7 {
  grid-column-start: span 7;
}

.l-8 {
  grid-column-start: span 8;
}

.l-9 {
  grid-column-start: span 9;
}

.l-10 {
  grid-column-start: span 10;
}

.l-11 {
  grid-column-start: span 11;
}

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

The resources used to find an answer:

Would be great if anyone could explain why the percentage widths make such a difference.

2 comments

@Michael_B 2017-07-13 23:02:02

fr

The fr unit works only with the free space in the container.

So in your code:

grid-template-columns: repeat(12, 1fr);

... the free space in the container is distributed equally among 12 columns.

Since the columns are only dealing with free space, grid-column-gap is not a factor. It was subtracted from the container width before the fr length was determined (spec reference).

Here's how the browser does the calculation:

(free space - gutters) / 12  = 1fr

%

When you're using percentages...

grid-template-columns: repeat(12, calc(100% / 12));

... the container is divided into 12 columns, each having a width of 8.33333%. This is an actual length, unlike the fr unit, which only deals with free space.

Both the column lengths and grid gaps are factored into the width.

Here's how the browser does the calculation:

8.33333% * 12 = 100%
         +
11 * 10px     = 110px

There's a clear overflow.

(Note: grid-*-gap properties apply only between grid items – never between items and the container. That's why the number of grid-gaps is 11, not 13.)

This works:

grid-template-columns: repeat(12, calc(8.3333% - 9.1667px));

Which breaks down to this:

  • 12 columns

  • the width of each column is determined by taking the full width of the container (100%) and dividing it by 12

    100% / 12 = 8.3333% (individual column width)
    
  • then subtract the column gaps (there are 11)

     10px * 11 = 110px (total width of column gaps)
    
    110px / 12 = 9.1667px (amount to be deducted from each column)
    

.grid {
  display: grid;
  grid-template-columns: repeat(12, calc(8.3333% - 9.1667px));
  grid-column-gap: 10px;
  grid-row-gap: 10px;
  justify-content: center;
}

.l-1 { grid-column-start: span 1; }
.l-2 { grid-column-start: span 2; }
.l-3 { grid-column-start: span 3; }
.l-4 { grid-column-start: span 4; }
.l-5 { grid-column-start: span 5; }
.l-6 { grid-column-start: span 6; }
.l-7 { grid-column-start: span 7; }
.l-8 { grid-column-start: span 8; }
.l-9 { grid-column-start: span 9; }
.l-10 { grid-column-start: span 10; }
.l-11 { grid-column-start: span 11; }
.l-12 { grid-column-start: span 12; }
[class*=l-] { border: 1px solid red; }
<div class="grid">
  <div class="l-6">Column 1</div>
  <div class="l-6">Column 2</div>
  <div class="l-3">Column 3</div>
  <div class="l-4">Column 4</div>
  <div class="l-3">Column 5</div>
  <div class="l-2">Column 6</div>
  <div class="l-1">Column 7</div>
  <div class="l-10">Column 8</div>
  <div class="l-1">Column 9</div>
  <div class="l-5">Column 10</div>
  <div class="l-5">Column 11</div>
  <div class="l-2">Column 12</div>
</div>

@Frank Lämmer 2018-01-28 21:36:09

Sorry, the percentage solution has a little flaw: The outer .grid container does not have the full width. It has a 5px gap on each side. When you remove "justify-content: center;" it adds the extra gap at the end of each line. I can imagine to correct this with a negative margin on .grid, but that's the stuff I wanted to avoid when using CSS Grid.

@Frank Lämmer 2018-01-28 21:46:05

Here is a demo that uses two different gap sizes and a border on the parent .grid container: codepen.io/esher/pen/pazqxw

@Michael_B 2018-01-28 22:17:09

Hi @FrankLämmer, good catch! There's no need for negative margins or anything like that. There was an error in my calculation. I've made the correction and updated the answer. Thanks!

@Frank Lämmer 2018-02-02 19:56:23

Yes Michael, this better can be done with some calculation. I made a version of your solution that uses calc and CSS vars here: codepen.io/esher/pen/qxbpQq

@edswartz 2017-07-13 21:13:02

According to this part of the spec the fr unit is not a length so it gets "calculated" AFTER determining the amount of free space available within the layout engine.

The variable you have created in your first example IS part of a calculation (100% of the width and dividing by 12) so it runs the calculation BEFORE passing to the layout engine.

When I say layout engine, I'm using it as a metaphor and don't want to confuse folks with the process of rendering that gets done by the browser. I'm just trying to say that in your first example you are presenting a series of numbers that get plugged into the browser to begin the rendering process and in your second example you are presenting more of an algorithm/function the browser can use to make its layout.

Related Questions

Sponsored Content

13 Answered Questions

[SOLVED] What's the difference between SCSS and Sass?

  • 2011-04-13 19:23:09
  • bruno077
  • 761617 View
  • 1792 Score
  • 13 Answer
  • Tags:   css sass

17 Answered Questions

[SOLVED] What is the difference between visibility:hidden and display:none?

  • 2008-09-25 12:37:47
  • Chris Noe
  • 553315 View
  • 1132 Score
  • 17 Answer
  • Tags:   css visibility

2 Answered Questions

[SOLVED] How can I get a background-image to be spanned over a grid-layout

  • 2019-04-08 06:23:15
  • Patrick3k
  • 361 View
  • 1 Score
  • 2 Answer
  • Tags:   html css css-grid

2 Answered Questions

[SOLVED] What's the best way of using a container in CSS Grid?

  • 2019-04-05 05:29:33
  • BeLambda
  • 62 View
  • 1 Score
  • 2 Answer
  • Tags:   html css css-grid

1 Answered Questions

[SOLVED] Using repeat in grid-template-areas instead of having to repeat grid cell names

  • 2019-03-18 05:43:39
  • Murray Chapman
  • 431 View
  • 3 Score
  • 1 Answer
  • Tags:   html css css-grid

1 Answered Questions

[SOLVED] How do I get CSS Grid column widths to match the content?

  • 2018-02-27 00:59:52
  • Chris Simeone
  • 797 View
  • 2 Score
  • 1 Answer
  • Tags:   css css-grid

1 Answered Questions

[SOLVED] CSS Grid auto-fit + minmax adds phantom row

  • 2017-11-20 19:07:25
  • PorcupineRending
  • 346 View
  • 0 Score
  • 1 Answer
  • Tags:   html css css-grid

1 Answered Questions

[SOLVED] Why does grid-gap change a column's width in CSS Grid?

  • 2017-09-11 23:32:57
  • edt
  • 2187 View
  • 2 Score
  • 1 Answer
  • Tags:   css css-grid

1 Answered Questions

[SOLVED] CSS Grid - Understanding the Grid for Text

  • 2017-07-17 16:07:29
  • Doe. J
  • 90 View
  • 1 Score
  • 1 Answer
  • Tags:   css grid

1 Answered Questions

CSS Responsive Percentage bug

Sponsored Content