2

in grid-template-columns, isn't the only thing matter are the proportions between the fractions ? and if so, why do the divs look different when the fractions are higher than 1 vs. smaller than 1 ?

.gizim {
  display: grid;
  grid-template-columns: 0.3fr 0.4fr 0.3fr;
  margin: 5em;
  grid-gap: 1em;
  width: 400px;
}
.gizim div {
    border: 1px solid red;
}
.gizim div:first-child {
    width: 100px;  
}

.gidoo {
  display: grid;
  grid-template-columns: 3fr 4fr 3fr;
  margin: 5em;
  grid-gap: 1em;
  width: 400px;
}
.gidoo div {
    border: 1px solid blue;
}
.gidoo div:first-child {
    width: 100px;  
}

JSBIN example

Nir O.
  • 1,563
  • 1
  • 17
  • 26

2 Answers2

0

I suspect this is is expected behaviour although an edge case

According to the spec.

<flex> values between 0fr and 1fr have a somewhat special behavior: when the sum of the flex factors is less than 1, they will take up less than 100% of the leftover space.

A track’s value is effectively a request for some proportion of the leftover space, with 1fr meaning “100% of the leftover space”; then if the tracks in that axis are requesting more than 100% in total, the requests are rebalanced to keep the same ratio but use up exactly 100% of it. However, if the tracks request less than the full amount (such as three tracks that are each .25fr) then they’ll each get exactly what they request (25% of the leftover space to each, with the final 25% left unfilled). See § 11.7 Expand Flexible Tracks for the exact details of how leftover space is distributed.

This pattern is required for continuous behavior as fr values approach zero (which means the tracks wants none of the leftover space). Without this, a 1fr track would take all of the leftover space; but so would a 0.1fr track, and a 0.01fr track, etc., until finally the value is small enough to underflow to zero and the track suddenly takes up none of the leftover space. With this behavior, the track instead gradually takes less of the leftover space as its flex factor shrinks below 1fr, smoothly transitioning to taking none of the leftover space at zero.

Indeed the spec recommends NOT using fraction fr values.

Unless this “partial fill” behavior is specifically what’s desired, authors should stick to values ≥ 1; for example, using 1fr and 2fr is usually better than using .33fr and .67fr, as they’re more likely to behave as intended if tracks are added or removed.

Clearly in your example the total is 1fr but the container still behaves as though it is less as the setting widths and having content wider that .3fr disrupts the calculation

Paulie_D
  • 107,962
  • 13
  • 142
  • 161
  • this seems to only explain situations where the total sum of all the fractions is smaller than 1. however, in my example, I used 0.3+0.4+0.3 = 1 so I don't see the fitness of this explanation to the scenario in question. – Nir O. Sep 23 '21 at 09:36
  • the quote that you have added in your edit ("using 1fr and 2fr .... more likely to behave as intended") adds yet more question marks whereas as developers we want a consistent, well-understood, predictable, behavior. – Nir O. Sep 23 '21 at 09:39
  • Yes but the setting widths and having content wider that .3fr disrupts the calculation - See https://codepen.io/Paulie-D/pen/vYZawpL – Paulie_D Sep 23 '21 at 09:40
  • definitely I came to that conclusion too :) the purpose of my question is to get a clear mathematic explanation of what exactly is different. – Nir O. Sep 23 '21 at 09:42
  • You aren't going to get one unfortunately. The spec says its "special" and a long technical explanation is probably beyond the scope here other than that already provided. – Paulie_D Sep 23 '21 at 09:43
  • let us see who will win the glory then :) – Nir O. Sep 23 '21 at 09:44
0

To understand this you need to understand a tricky behavior related to 1fr. 1fr is equivalent to minmax(auto,1fr) as explained here: Why does minmax(0, 1fr) work for long elements while 1fr doesn't? which means "the track cannot be smaller than the size of the grid item"

You are wondering how this answer your question so Let's start with an example to illustrate the issue.

.gizim{
  display: grid;
  grid-template-columns: 0.3fr 0.4fr 0.3fr;
  margin: 5px auto;
  grid-gap: 1em;
  width: 400px;
  border:1px solid;
}

.gizim div {
  border: 1px solid red;
  min-height:20px;
}

.alt {
  grid-template-columns: minmax(0,0.3fr) minmax(0,0.4fr) minmax(0,0.3fr);
}
<div class="gizim">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>
<div class="gizim">
  <div>1</div>
  <div>2</div>
  <div>333333333333333</div>
</div>
<div class="gizim alt">
  <div>1</div>
  <div>2</div>
  <div>333333333333333</div>
</div>

The first case will behave like you want because all your xfr are bigger than auto. Now let's understand the second case.

First we need to identify the "leftover" (https://www.w3.org/TR/css3-grid-layout/#leftover-space). It's the space left if we first consider the column sized to their default content. Something like below:

.gizim{
  display: grid;
  grid-template-columns: auto auto auto;
  justify-content:start;
  margin: 5px auto;
  grid-gap: 1em;
  width: 400px;
  border:1px solid;
}

.gizim div {
  outline: 1px solid red;
  min-height:20px;
}
<div class="gizim">
  <div>1</div>
  <div>2</div>
  <div>333333333333333</div>
</div>

You can see the "leftover" space at the right. If we do some calculation we can find 400px - 2x16px(gap) - 120px(width of 3) = 248px so 1fr = 248px*. This will give us the logical result of:

 0.3fr = 74.4px
 0.4fr = 99.2px

It's important to note that the third element has an initial width bigger than .3fr so he will keep that width while the other will increase in width following the above calculation:

.gizim{
  display: grid;
  grid-template-columns: 0.3fr 0.4fr 0.3fr;
  justify-content:start;
  margin: 5px auto;
  grid-gap: 1em;
  width: 400px;
  border:1px solid;
}

.gizim div {
  outline: 1px solid red;
  min-height:20px;
}
<div class="gizim">
  <div>1</div>
  <div>2</div>
  <div>333333333333333</div>
</div>

*In reality the calculation is more complex to explain in detail but the important part here is that the content play a role in defining how the fr will behave but if we use minmax(0,xfr) you will get the expected result because we are no more considering the content.


Such issue doesn't occur when using more than 1fr because we are going to use more than the "leftover" space so we will for sure fill all the columns but still the content play a role:

.gizim{
  display: grid;
  grid-template-columns: 3fr 4fr 3fr;
  margin: 5px auto;
  grid-gap: 1em;
  width: 400px;
  border:1px solid;
}

.gizim div {
  border: 1px solid red;
  min-height:20px;
}

.alt {
  grid-template-columns: minmax(0,3fr) minmax(0,4fr) minmax(0,3fr);
}
<div class="gizim">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>
<div class="gizim">
  <div>1</div>
  <div>2</div>
  <div>333333333333333</div>
</div>
<div class="gizim alt">
  <div>1</div>
  <div>2</div>
  <div>333333333333333</div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • I am not sure how you calculated `1fr = 248px` because in the relevant example, the column width was "auto" so 1fr may not have any meaning as it is not in comparison to any other column – Nir O. Sep 23 '21 at 12:03
  • in other words, you didn't present how 1fr has a "special" meaning, that 10fr (as an example...) cannot have. – Nir O. Sep 23 '21 at 12:17
  • @NirO. 1fr has no special meaning .. 1fr is the unit so we start by calculation 1fr to find the 10fr, 0.3fr,etc .. I added the formula to find the 1fr. It's more complex than what I mentioned because I will need twice this post to explain how the "leftover" space is calculated which is used by the `fr` – Temani Afif Sep 23 '21 at 15:07
  • in the `0.3fr+0.4fr+0.3fr` case, the divider of the leftover is 1, causing "hypothetical fr size" become `248px` (https://www.w3.org/TR/css3-grid-layout/#leftover-space paragraph #3) so when a big (`248*0.3 = 74.4px`) number is enforced as min (via `minmax`), the min would be `74px`, making columns wider than expected. in the `3fr+4fr+3fr` case, the divider of the leftover is 10, causing "hypothetical fr size" become `24.8px`. so when a smaller (`24.8*0.3 = 7.44px`) number is enforced as min, layout works as expected – Nir O. Sep 24 '21 at 14:12