简体   繁体   中英

Flexbox: growing div with flex-basis: 0px expands too far when there's lots of content inside it

Consider the following HTML ( JSFiddle ):

 <div style="display: flex; align-items: flex-start; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan; flex-shrink: 0"> Yo </p> <div style="display: flex; flex: 1 1 0px; align-items: flex-start; background-color: green; overflow: visible"> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> </div> </div> <!-- magenta 500px indicator here added for comparison of width --> <div style="width: 500px; height: 5px; background-color: magenta; margin-bottom: 10px"></div>

We have a 500px wide flex container, and inside that container are two children: one which takes up 50px with flex-shrink: 0 and one which is supposed to take up the remaining space (in this case, 450px) using flex: 1 1 0px . However, it's actually expanding slightly further out, and its actual rendered width is 472.83px. If you add more content inside it, it gets bigger and bigger, unless you set a width: 0px on it, in which case its rendered width is 450px as expected.

  1. Why is this container's width expanding to be larger than 450px? I thought that using flex-basis: 0px meant that the effective size for flex purposes would always be 0px, and as such I would expect the container to grow to fill its parent's available width regardless of its content.
  2. With 13 of the <p> tags inside the container, it still has the 450px expected with, even though the text overflows (as expected). However, with the 14th <p> tag, the container starts growing, and after the 14th it keeps growing, by about 33.77px per <p> tag. What limit is getting hit on the 14th tag that causes the container to behave this way?
  3. Why does setting a width: 0px on this container cause it to have 450px width as I expected? I thought flex-basis always took priority over width .

I originally thought this might be a browser rendering issue, but the issue happens the same way in Chrome, Firefox, and Safari.

The second flex item (green) overflows the primary container for two reasons:

  1. That's the minimum width it can achieve with the content it has before flexibility properties are applied . In other words, the browser establishes the main size of the container before factoring in flex-shrink: 0 .

    在此处输入图像描述

  2. The default minimum width of flex items is min-width: auto (meaning the item can't be smaller than the size of its content), and the nested flex container is also a flex item . When you override the default—with min-width: 0 , for example—it fits.

    在此处输入图像描述

First of all, you can remove the flex property and you will still get the same result. I am also removing the properties that won't affect the result as well:

 <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan; flex-shrink: 0"> Yo </p> <div style="display: flex; background-color: green; "> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> <p style="flex-shrink: 0">This is some text</p> </div> </div> <!-- magenta 500px indicator here added for comparison of width --> <div style="width: 500px; height: 5px; background-color: magenta; margin-bottom: 10px"></div>

Now, to understand what is happening, we need to add the properties one by one.

The initial configuration is that all the elements need to shrink so we get the following:

 <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <!-- magenta 500px indicator here added for comparison of width --> <div style="width: 500px; height: 5px; background-color: magenta; margin-bottom: 10px"></div>

You can clearly notice that in all the 3 cases, the text will wrap in order to try to get inside the 500px . Notice the difference in the wrapping between the first and second case.

The second case is the maximum wrapping you can have with your text since by default we cannot split words. And if you start adding more text, you will have overflow like in the 3rd case because there is no room for wrapping and for shrinking.

Now let's introduce flex-shrink: 0 for each case

The first one:

 .shrink p { flex-shrink:0; }
 <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <br> <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;flex-shrink:0"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <br> <div class="shrink" style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <!-- magenta 500px indicator here added for comparison of width --> <div style="width: 500px; height: 5px; background-color: magenta; margin-bottom: 10px"></div>

By adding flex-shrink: 0 to the blue element we still have some space for the green element so it won't overflow and by adding flex-shrink: 0 to its content it will overflow but the green element won't get bigger (due to the shrink effect as well)

Now the second case which is the case of your question:

 .shrink p { flex-shrink:0; }
 <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <br> <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;flex-shrink:0;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <br> <div class="shrink" style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;flex-shrink:0;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <!-- magenta 500px indicator here added for comparison of width --> <div style="width: 500px; height: 5px; background-color: magenta; margin-bottom: 10px"></div>

Notice how adding flex-shrink: 0 to the blue element already create an overflow of the green one because this one cannot be smaller than its min content (when all the text is already wrapped). This is the default behavior of flex items. Adding flex-shrink:0 to its content won't change nothing because a flex item will always try to shrink but not beyond its min-width.

That's why adding min-width:0 (or width:0 ) can fix this issue:

 .shrink p { flex-shrink:0; }
 <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <br> <div style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;flex-shrink:0;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <br> <div class="shrink" style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;flex-shrink:0;"> Yo </p> <div style="display: flex; background-color: green; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <br> <div class="shrink" style="display: flex; background-color: blue; width: 500px;"> <p style="width: 50px; background-color: cyan;flex-shrink:0;"> Yo </p> <div style="display: flex; background-color: green;min-width:0; "> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> <p >This is some text</p> </div> </div> <!-- magenta 500px indicator here added for comparison of width --> <div style="width: 500px; height: 5px; background-color: magenta; margin-bottom: 10px"></div>

Now, I let you imagine the 3rd case where we add more content. We simply increase the min-width constraint a little each time and we make the green element bigger.

Related: Why don't flex items shrink past content size?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM