Mateusz Kirmuć

Posted on

CSS Grid: fr unit — beyond basics

Hello. In today's article, I want to extend the knowledge about fr unit contained in my previous post. Here I want to discuss some less common cases related to this subject. I hope you will find it useful.

Fr unit is not allowed in CSS calc function.

Let’s imagine we have a simple layout composed of two vertical and one horizontal grid track. Each column has an equal size of 1fr as in the example below.

Then we came up with the idea, that will be great to shrink one column by 20px, leaving some extra space on the right side of the container.

How can we accomplish this change? One of the potential approaches is the calc function. This is a great method to calculate values using simple math operations. Calc function accepts values of different data types including those representing distance. Let's add something like this:

``````.grid-container {
...
grid-template-columns: 1fr calc(1fr - 20px);
}
``````

What will happen when we try to use fr unit in the calc function? Unfortunately, the function won’t accept this expression. The reason is the fr unit is not compatible with the length data type (or any other data type that the calc function can accept). Even though it may seem that the fr unit represents the length (part of available space) it cannot be used in the calc function because of the not accepted data type.

Fr unit with indefinite size container

In all examples presented by me so far CSS Grid algorithm has a relatively easy job with calculating flexible track size. All it needs to do was calculate the length of 1fr and then multiply this value by flex factor for every flexible track. However, there is one condition for this to work — container size must be definite. In the case of CSS Grid, this means that the container must have directly specified width or height or at least be a block-level element (the last one concerns only for horizontal axis)*.

Now, let’s consider the case when container size is indefinite. Using the following example I want to show you how the CSS Grid algorithm computes the lengths of flexible columns. Below we have a container with the fixed height, described using `display: inline-grid` (inline-level element). This container contains a grid with one non-flexible and two flexible columns. Each of the flexible columns contains some text content inside**.

``````.container {
display: inline-grid;
grid-template-columns: 200px 2fr 1fr;
...
}
``````

The following image shows what this layout would look like before the space distribution of flexible columns is started. You can notice that the 2fr column isn’t yet twice as large as the 1fr column because so far each flexible column adjusts its width to content.

The size of each text content is fixed and the algorithm will use those values to calculate a length of 1fr. First, it divides each text width with the respective flex factor. Such obtained values are compared and the highest one will be used to represent 1fr.

Finally calculated 1fr value will be used to define the sizes of the flexible columns. Each flexible column will take a width equal to 1fr multiplied by the respective flex factor. Notice that now the middle column is much wider increasing the total width of the container.

Flex factors can be fractions.

It’s important to know that we are not forced to always use integers as flex factors. Flex factors can be fractions. In this case, the process of calculating the width of flexible tracks depends on the sum of all factors. When the sum is greater than 1, this process is similar. First, the length of 1fr is calculated by dividing leftover space by the sum of flex factors. Then, each flexible track receives a size equal to the product of the calculated 1fr value times the respective flex factor. Below is a simple example with one non-flexible and two flexible columns.

``````.container {
...
grid-template-column: 100px 1.4fr 2.2fr
width: 400px
}
``````

``````1fr = leftover space / sum of flex factors

1fr = (400px - 100px) / (1.4 + 2.2)

1fr = 83.33px
``````

However, when the sum of flex factors is less than 1, each flexible track receives a size equal to the product of leftover space times the respective flex factor. There is no need to calculate the length of 1fr. Notice in the example below that the total size of all tracks is less than the size of the container.

``````.container {
...
grid-template-column: 100px 0.4fr 0.5fr
width: 400px
}
``````

``````flexible column width = leftover space * flex factor
``````

The size of a flexible track cannot be smaller than its fixed-size content.

At the end of this article, I want to discuss the relation between the size of the flexible track and its static-size content. Defining grid track as flexible, we assume that it takes some part (or all) of leftover space. However, it’s important to know that in some cases, the flexible track may take more space than we expect. This is happen because a flexible track cannot be smaller than its fixed-size content. Let’s look at the following example.

``````.container {
...
grid-template-column: 1fr;
}
``````

As you can see, a flexible column should take all the available space (equal to container width as this layout consists of only 1 column). However, the column contains fixed-size text content which is wider than the available space. Thus, the final width of a flexible column is larger than the container width.

Thank you for reading this short article. If you want to read more content like this you can follow my dev.to or twitter account. Also, feel free to give me any form of feedback. I'd love to read any comments from you. See you soon in my next article!

PS. If you would like to support my work, I will be grateful for a cup of coffee. Thank you. ❤️

*By default block-level element occupies the entire horizontal space of its parent element. This not concerns vertical axis. Block-level element without specified height will be indefinite in the vertical axis.

**It’s important to remember that such layout requires that text content is placed inside grid-items, not in grid columns directly. I have chosen not to mention about grid-items to simplify this example.