Taking 3 items of 100px height in a grid with grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
, and putting that grid into a flex container with flex-wrap: wrap;
will push the flex container to have a height of 332px, instead of the 100px height of the grid (tested chrome and safari).
I just banged my head on this problem before finding the solution : set flex-wrap: nowrap;
. I do realized it also have sometimes to do about flex-direction: columns;
, but I don’t understand why this flex properties has effects on a grid. Can someone explains? Also open to cleaner fixes.
.flex-container {
background-color: #aaa;
display: flex;
flex-direction: column;
width: 100%;
flex-wrap: wrap;
/*problem is here, solved with "nowrap"*/
}
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 16px;
padding-inline-start: 0px;
margin: 0;
}
.item {
background-color: #cc0;
height: 100px
}
<span>flex-container should have a height of 100px, but has 332px instead because of flex-wrap set to "wrap"</span>
<div class="flex-container">
<ul class="grid-container">
<li class="item"></li>
<li class="item"></li>
<li class="item"></li>
</ul>
</div>
2
Answers
add width to
.grid-container
It’s related to the default stretch alignment of flexbox. If you change the alignment of the grid container you can see what is happening:
The grid is no more full width and the result is logic. Even if you use
nowrap
you will have the same result.The trick is that your grid container is a flex item that has no explicit width definition and is using an
auto-fill
configuration. This configuration means that you grid need to first get a width defined by it’s environment then based on that it will define the columns. In other words, the content play no role in defining the width of the element.In your case, the stretch alignment is defining the width making the element take all the space available. Removing the stretch alignment will remove the only width definition and your grid will get the minimum size possible (the size of one column).
Now the difference between
wrap
andnowrap
is how the algorithm works. I will try to use easy words to explain it.When using
nowrap
, you have a single line configurationThis configuration is somehow easy because the flex container will first create one line taking all the available space. Then inside that line the elements will get placed (in your case the grid container is stretched) and we can easily find the final height of the line and the container.
When using
wrap
, you have a multi-line configuration even if in the end you have only one lineThis will make the algorithm tricky because when we have a multi-line configuration we have to also identify the size of the lines (in your case it’s the width since you have a column configuration) and we said that the grid container doesn’t have any explicit width so it cannot size the line but the line will get size with the stretch algorithm as well. Not the same stretch of the grid container!
flex lines obey to the
align-content
property and by default is has the value stretch and flex items obey toalign-items
(oralign-self
) property which also has a stretch default alignment. So we have two nested stretch alignment.In the below I will update the
align-content
and we get the same behavior as my first snippet.This configuration makes the algorithm a bit complex because we first need to find the height of the lines without the stretch alignment (the
332px
you get) then we apply the stretch alignment to the lines increasing their cross size (their width). The increase of this width will also increase the width of the grid since this one is also stretched inside the line and here comes the trick! The grid container have more space to create more columns BUT we don’t get back to calculate the height again because it was already done in a previous step hence we keep that332px
of height.It may sounds strange but the double stretch alignment combined with
auto-fill
created a complex and very specific situation where we first compute the height that we don’t update later to avoid getting into an infinite loop.To avoid such situation, you either keep a single line configuration by using
nowrap
or you explicitly define the width of your grid container (width: 100%
will do the job if you won’t have more items in your flex container) or you simply get rid offlex-direction: column
which is not really need in your case. But you have to addflex-grow: 1
to the grid container.The stretch alignment works on the cross axis and when using a row configuration it will be the height and flex item will have a shrink-to-fit behavior on the main axis but you can make them grow to fill the available space
The above configuration have less complexity and is more logic for your situation and it won’t create any "strange" result
Here is another related question with a similar situation if you want more headaches: flex-wrap causes children to double in height