So I am defining a layout in CSS Grid which needs this particular row to have identically sized inputs. I can do the math and just specify percentages and it works fine (see
Add min-width:0
to input and you should fix the percentage value so they are exacltly the same as the fr
. You have 31fr
so 1fr
is about 100/31 = 3.225%
.A {
grid-area: a;
}
.B {
grid-area: b;
}
.C {
grid-area: c;
}
.Exchange_Row {
display: grid;
grid-template-columns: 1fr 9fr 10fr 10fr 1fr;
grid-template-areas: "a a b c ."
}
.Exchange_Row.percentage {
grid-template-columns: 3.225% 29.03% 32.25% 32.25% 3.225%;
}
input[type=text] {
border: solid;
min-width:0;
}
<div style="width: 90%; border: solid; border-radius: 5px; padding: 5px;">
<div id="currencyRow" class="Exchange_Row">
<input type="text" class="A" value="A" />
<input type="text" class="B" value="B" />
<input type="text" class="C" value="C" />
</div>
</div>
<div style="width: 90%; border: solid; border-radius: 5px; padding: 5px;">
<div id="currencyRow" class="Exchange_Row percentage">
<input type="text" class="A" value="A" />
<input type="text" class="B" value="B" />
<input type="text" class="C" value="C" />
</div>
</div>
This is related to Automatic Minimum Size of Grid Items and how grid items are sized. An input element has a default width set by browser considered as a minimum size (it's also the same with flexbox). This size is used to define the column size of the 10fr
.
If we refer to the above links:
Once the grid items have been placed, the sizes of the grid tracks (rows and columns) are calculated, accounting for the sizes of their contents and/or available space as specified in the grid definition.
Both columns (defined by 10fr
) will be sized considering their content (the input element) but the first two columns (1fr
and 9fr
) cannot be sized using the input because this one is spaning both of them and not only one of them. To say this differently: the 1fr
and 9fr
columns don't have any explicit content thus they will be sized according to the available space then the input will match this space.
In other words, the first input is sized based on the 1fr
and 9fr
but the other input is sizing the 10fr
.
By adding min-width:0
we remove the Automatic Minimum size constraint thus there is no more content size to account for and all the grid columns will get sized using the available space then the inputs will match that size.
Adding width:100%
will also fix the issue but differently. In this case, we tell the input to have its width based on its containing block (the grid item) so we need to first define the size of the grid item (considering the available space) then resolve the percentage value to define the input size.
This will happen with any configuration even if you change the fr
values:
.A {
grid-area: a;
}
.B {
grid-area: b;
}
.C {
grid-area: c;
}
.Exchange_Row {
display: grid;
grid-template-columns: 5fr 5fr 1fr 1fr 1fr;
grid-template-areas: "a a b c ."
}
.Exchange_Row.another {
grid-template-columns: 50fr 50fr 3fr 1fr 1fr;
}
input[type=text] {
border: solid;
}
<div style="width: 90%; border: solid; border-radius: 5px; padding: 5px;">
<div id="currencyRow" class="Exchange_Row">
<input type="text" class="A" value="A" />
<input type="text" class="B" value="B" />
<input type="text" class="C" value="C" />
</div>
</div>
<div style="width: 90%; border: solid; border-radius: 5px; padding: 5px;">
<div id="currencyRow" class="Exchange_Row another">
<input type="text" class="A" value="A" />
<input type="text" class="B" value="B" />
<input type="text" class="C" value="C" />
</div>
</div>
Even if we define bigger value for the first input, the other will always win because they will define the size of their own grid column and the first one will simply take the remaining.
UPDATE
Another way to explain this (as comment by @Michael_B) is that 1fr
unit is equivalent to minmax(auto,1fr) which means that for the 10fr
column we have the auto
size of the content as a lower bound which isn't the case for the two first columns since they don't have the input as their content.
We can use minmax(0,1fr)
to overcome this instead of using min-width:0
.A {
grid-area: a;
}
.B {
grid-area: b;
}
.C {
grid-area: c;
}
.Exchange_Row {
display: grid;
grid-template-columns: minmax(0,1fr) minmax(0,9fr) minmax(0,10fr) minmax(0,10fr) minmax(0,1fr);
grid-template-areas: "a a b c ."
}
.Exchange_Row.percentage {
grid-template-columns: 3.225% 29.03% 32.25% 32.25% 3.225%;
}
input[type=text] {
border: solid;
}
<div style="width: 90%; border: solid; border-radius: 5px; padding: 5px;">
<div id="currencyRow" class="Exchange_Row">
<input type="text" class="A" value="A" />
<input type="text" class="B" value="B" />
<input type="text" class="C" value="C" />
</div>
</div>
<div style="width: 90%; border: solid; border-radius: 5px; padding: 5px;">
<div id="currencyRow" class="Exchange_Row percenage">
<input type="text" class="A" value="A" />
<input type="text" class="B" value="B" />
<input type="text" class="C" value="C" />
</div>
</div>