Understanding CSS Grids Fractional Units (FR) the easy way
We have seen this year a quick adoption of CSS Grids (As of this writing, globally close to 80%). I’ve been banging my head to grasp the new proposal, since it comes with a bunch of features, and the new measuring unit that comes with it, fractional units (FR).
MDN definition states Fractional unit as:
The new
fr
unit represents a fraction of the available space in the grid container.
Ok, cool. But what does it actually mean? Let’s go back to 4th and 5th grade math and remember about fractions.
I don’t know if they ever taught you this way, but a good way to visualize fractions is looking at pizza. The pizza is going to be our grid.
The whole pizza represents the total available space. Right now, no one has eaten a slice of it, nor sliced it, therefore the whole available pizza is 1 fr or 100%.
This exact Pizza is represented the following way:
CSS:
// CSS:
.container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-gap: 1em;
}
div {
background-color: #7986CB;
width: 100%;
height: 100%;
}
HTML:
<section class=”container”>
<div></div> <div></div> <div></div>
<div></div> <div></div> <div></div>
<div></div> <div></div> <div></div>
</section>
The code you see on the top says: “give me the whole pizza”. The first row and column make it occupy 100% of the space. This creates a grid with 1 column and 1 row. Since each row and column is 1fr, and no other column or row is defined in the space, it takes 100% of it.
Hold on Sherlock, what happens with those bunch of <div> that are inside that <section>?
Glad you asked! Well, imagine those <div> as the number of pizza slices we want to eat, and the grid-template-column and grid-template-row as the number of slices we chop our pizza.
In this case, we have defined our pizza (grid) to chop one big slice (Theoretically speaking, one whole pizza is one big slice). To better illustrate this, check this Tom and Jerry episode out:
Since we have only one slice, the other <div> won’t get their share and they won’t be displayed! In other words, you can’t give a slice of pizza that doesn’t exist, can you 😉? That means that those other <div> don’t exist for the grid.
Let’s get back to Tom and Jerry. Both of them have decided to eat pizza (Spike doesn’t know about it, yet). They’re debating how are they going to share it. Reasonably, each one of them want their own portion, so the first thing they do is slice the pizza.
The number of slices the pizza has, is the series of numbers we add to the grid-template-rows and grid-template columns:
// CSS:
.container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-gap: 1em;
}
div {
background-color: #7986CB;
width: 100%;
height: 100%;
}
We have sliced the pizza in 2. Now we have 2 numbers in the grid-template-columns and grid-template-rows, and we’ve made each one of them take half! But take a look! Tom and Jerry are merely debating and haven’t eaten any pizza slices yet (more on that soon)!
Who said that when we slice the pizza in 2, it needs to be 2 perfect halves? Tom understands that really well, and is debating for a bigger slice. How big of a slice he wants to get, is going to be proportional to the fr units he assigns it to.
Therefore, the number that Tom gives to his pizza slice will affect what Jerry gets. Even if the pizza is sliced by 2 (How many numbers you add to the grid-template-columns and grid-template-rows), it doesn’t mean that it needs to be sliced 50% and 50%.
Tom (Column 1, Row 1) decides to take three times as many as Jerry (Column 2, Row 2), he’d define his pizza, or his grid like this:
// CSS:
.container {
display: grid;
// Tom 3fr; Jerry 1fr
grid-template-columns: 3fr 1fr;
grid-template-rows: 3fr 1fr;
grid-gap: 1em;
}
div {
background-color: #7986CB;
width: 100%;
height: 100%;
}
On the other hand, Jerry fights back, and decides to take twice as many as Tom:
// CSS:
.container {
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-rows: 3fr 1fr;
grid-gap: 1em;
}
div {
background-color: #7986CB;
width: 100%;
height: 100%;
}
Mathematically speaking, each fr that gets in the grid-template-columns(or rows) represent part of the denominator of the fraction in total that is in the grid-template-columns and grid-template-rows . And each numerator is going to be the fr unit assigned to it. In other words, you are going to add all the fr units and use them as denominator, while each individual fr will be used as numerator for the fraction.
😵😵😵😵😵😵😵😵😵😵😵😵😵😵😵😵😵😵
Woah! In English, please!
Better to explain with an example💡!
If we keep up with Jerry’s division, Jerry gets twice as many as Tom (2fr), representing 66.67% of the total pizza, or 2/(1+2). Tom gets half as many as Jerry (1 fr) and it represents a 33.33% of the total pizza, or 1/(1+2).
Here are more quick examples to help you out:
// Tom gets 1/(1+4) = 1/(5) = 0.2 = 20%
// Jerry gets 4/(1+4) = 4/5 = 0.8 = 80%
grid-template-columns: 1fr 4fr;// This is the same as the one above:
// Tom gets 2/(2+8) = 2/(10) = 0.2 = 20%
// Jerry gets 8/(2+8) = 8/10 = 0.8 = 80%
grid-template-columns: 2fr 8fr;// Tom gets 3/(3+5) = 3/(8) = 0.375 = 37.5%
// Jerry gets 5/(3+5) = 5/8 = 0.625 = 62.5%
grid-template-columns: 3fr 5fr;grid-template-columns: 1fr 4fr;
Getting the hang of it? Well, we’re almost there!
Now, imagine Spike comes to the fray, and wants to take his share. This time, Spike fights for 4 times as much as Tom and Jerry:
Therefore, we add one more column or row to the grid.
// CSS:
.container {
display: grid;
// Tom, Jerry, and Spike, respectively
grid-template-columns: 1fr 1fr 4fr;
grid-template-rows: 1fr 1fr 4fr;
grid-gap: 1em;
}
div {
background-color: #7986CB;
width: 100%;
height: 100%;
}
This will display up to a third div in the column space, and up to a third div in the row space:
<section class=”container”>
<div></div> <div></div> <div></div>
<div></div> <div></div> <div></div>
<div></div> <div></div> <div></div>
</section>
Note: until this moment, no one has taken a slice, but merely divided it. This is important! Keep reading…
One debate that we haven’t settled out is… how large the pizza is. As of today, pizza comes in different sizes. Which are akin to the grid’s pixel/em width (columns are affected), and height (rows are affected) properties.
Let’s say that they went for a Medium Sized Pizza (Hey, they were broke 💰!), width = 1000 px. Spike set his deal in stone and ate his slice. His slice was about 667px width ~ 41.68em.
Now, that someone has taken a slice, the code looks like this:
// CSS:
.container {
display: grid;
width: 62.5em;
// Tom, Jerry, and Spike, respectively
grid-template-columns: 1fr 1fr 41.66em
grid-template-rows: 1fr 1fr 41.66em;
grid-gap: 1em;
}
div {
background-color: #7986CB;
width: 100%;
height: 100%;
}
Right now, the code above outputs the exact same thing as the one before. With the subtle difference that now Tom and Jerry must fight for the remaining slices, and that we’ve set the grid to be a total of 1000px width.
Jerry wanted to make Tom’s life miserable, and sliced his portion 4 times bigger than Tom’s, resulting in the following
// CSS:
.container {
display: grid;
width: 62.5em;
// Tom, Jerry, and Spike, respectively
// Spike: 41.67em
// Jerry: 4fr = 266.67 px
// Tom: 1fr = 66.67 px
grid-template-columns: 1fr 4fr 41.66em
grid-template-rows: 1fr 4fr 41.66em;
grid-gap: 1em;
}
div {
background-color: #7986CB;
width: 100%;
height: 100%;
}
As you can see, there’s a difference between slicing, and eating your slice. “Slicing” is using the fr, while “eating the slice” is the equivalent of assigning an actual em/rem/vh/vw/px value to the grid-template-columns and grid-template-rows!
Putting it all together:
<style>
html, body {
width: 100%;
height: 100%;
}section {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 1fr 4fr 41.66em;
grid-template-rows: 1fr 4fr 41.66em;grid-gap: 1em;
}div {
background-color:#7E57C2;
width: 100%;
height: 100%;
box-sizing: border-box;
}
</style>
</head><section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
That’s our resulting HTML! For the reason that we’re also adding properties to the row, they show as they do above.
// CSS:
.container {
display: grid;
grid-template-columns: 1fr 1fr
grid-template-rows: 1fr 2fr 2 fr;
grid-gap: 1em;
}
div {
background-color: #7986CB;
width: 100%;
height: 100%;
}
This other example, will create 2 columns and 2 rows with 50% in each of them.
<style>
html, body {
width: 100%;
height: 100%;
}section {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-gap: 1em;
}div {
background-color:#7E57C2;
width: 100%;
height: 100%;
box-sizing: border-box;
}
</style>
</head><section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
Of course! The grid-template-columns and grid-template-rows do not need to be the same! In fact, most of the time they won’t.
You can see them as having 2 different pizzas:
// CSS:
html, body {
width:100%;
height: 100%;
}section {
display : grid;
width: 1000px;
height:100%;
grid-template-columns: 2fr 2fr 2fr;
grid-template-rows: 2fr 1fr;
grid-gap: 0.5em;
}div {
background-color: #7986CB;
width: 100%;
height: 100%;
}<!-- HTML -->
<section>
<div></div><div></div><div></div>
<div></div><div></div><div></div>
</section>
That’s it! Let’s wrap it up:
- Fractional Units are based on the remaining space available to it. Think of it like slicing pizza.
- Remember that not because you sliced pizza in two or three parts, they are in the same size!
- Because you sliced the pizza, it doesn’t mean that they’ve been taken! Once a pizza slice is taken (Assigned a px/em/rem/vh/vw value), the fr will be of the remaining pizza!
- If you add more <div> (The equivalent of pizza slices) than you define in the grid, they won’t be displayed. You can’t give away pizza slices that do not exist.
- grid-template-columns will be affected by the width property of the grid.
- grid-template-rows will be affected by the height property of the grid.