Say you have a very simple CSS grid layout with one column fixed at 300px
and another taking up the rest of the space at 1fr
.
.grid {
display: grid;
grid-template-columns: 1fr 300px;
}
That’s somewhat robust. That 1fr
column will take up any remaining space left behind by the fixed 300px
column. It’s true that the auto
value would do the same, but auto
isn’t quite as robust since it’s size is based on the content inside. So, if you had too little content, then your column might not fill the entire space you want it to. But while 1fr
is slightly more robust, it won’t quite protect you from content that is too big!
Here’s the grid behaving just fine with some text content:
Now, watch that right column get blown off the page when we drop a gigantic image in that column:
That one is easy to fix — and you may never even have it happen to you, because this snippet is so common in our stylesheets:
img {
max-width: 100%;
}
But some elements aren’t so friendly. Take the notorious <pre>
tag. Say we toss one of those in our 1fr
column with a long string of text. We’re back to wrecked:
This time, things aren’t so easily fixed! Even attempting to limit the width and hide the overflow of <pre>
isn’t going to help:
pre {
max-width: 100%;
overflow: hidden;
}
The real fix isn’t all that difficult — we only need to understand what is happening. I can’t promise I’m explaining this 100% accurately, but the way I understand it, the minimum width of a grid column is auto
. (The same is true for flex items, by the way.)
And since auto
is entirely based on content, we can say it is “indefinitely” sized, its dimensions flex. If we were to put an explicit width on the column, like 50%
or 400px
, then we would say it is “definitely” sized.
To apply our fix, we need to make sure that there is the column has a definite minimum width instead of auto
.
So, we can either fix it like this:
.grid {
/* auto minimum width, causing problem */
grid-template-columns: 1fr 300px;
/* fix: minimum width of 0 */
grid-template-columns: minmax(0, 1fr) 300px;
}
Or, we put an actual min-width
on the element that occupies that grid column. In our simple demo, the <main>
element automatically places itself in that first column as it is the first child of the grid.
That give us this:
main {
min-width: 0;
}
I think it’s a bit more robust to do this at the grid definition level. Anyway, it does the trick! See how the <pre>
tag now respects the width of the column and can overflow as expected?
Nice.
Thanks for bleeding on the cutting edge first, so we don’t have to
I love this, and I love CSS grid, but that do we do with the IE 11 crowd? I know… I know, but as long as Microsoft still supports it, I’m required to support it as well.
Have you seen our entire series on this?
The explanation here is that the minimum size of an
fr
unit is auto. Grid then looks at themin-content
size of the item. If the item has a size (you’ve given it a width) or has something in it with a size such as an image, the min-content size might be much bigger than the share of available space you think 1fr will give you. It’s easy to think of 1fr as being “one part of the space in the grid container” when it is really one part of the space left over.If there is space to grow then the tracks grow from that min-content size assigning space.
Using minmax, as you have pointed out, is the best thing to do if you want to forcibly have equal width tracks, as that says “I want this track to have a min-content size of 0”, you could potentially in that situation end up with overflows as you lose the squishiness.
Thanks for putting in the effort and coming up wth this interesting use case…
Awesome! Thanks for saving us the bother ;D
You reversed the columns from “300px 1fr” to “1fr 300px”. What is the significance / difference of that?
Thanks for this!
Helped us fix a flexbox bug we were seeing in which the height was supposed to be calculated by flex: 1 but was instead becoming the entire height of an occluded scroll component.
Was only happening in Firefox.