简体   繁体   中英

CSS flexbox (flex-grow / flex-basis) - Same width, but doesn't wrap anymore

I use flexboxes to organize elements on my page.

I want the flexboxes to use all available horizontal space, so I add flex-grow:1 .

Then I want each item on the same line to be of the same size (eg 50% each if there is two items, 33% if there is three, etc), so I add flex-basis:0 .

But at the third step, the items don't wrap anymore. If I change the window width, the number of items per line stays always the same, and their content is squeezed. I don't want that. I want an item to be put on the next line when their width become smaller than it's content, as it works in the first two steps. I tried playing with flex-shrink and other things, without success.

What can I do ? Thanks !

Answer TL;DR: Adding min-width: fit-content works !

JSFiddle

Although you have flex-wrap set to wrap , there is no width defined for the flex items ( li ), and you have flex-basis set to 0. This means that the initial main size of the flex items is 0. It won't wrap because it can shrink to zero (even if the flex-shrink property is 0).

Solution #1

One thing you can do is set the flex-basis property to content or auto .

li { flex-basis: auto; }

This tells the flex item to factor in the width of its content.

jsfiddle demo

flex-basis

The initial main size of the flex item.

auto

When specified on a flex item, the auto keyword retrieves the value of the main size property as the used flex-basis . If that value is also auto , then the used value is content .

content

Indicates automatic sizing, based on the flex item's content.

Note: Note that content was not present in the initial release of Flexible Box Layout, and thus some older implementations will not support it. The equivalent effect can be had by using auto together with a main size (width or height) of auto .

This diagram from the flexbox spec tries to explain the difference between flex-basis: 0 and flex-basis: auto . Here's a more complete explanation.

在此输入图像描述


Solution #2

Another method to vertically stack flex items on smaller screens is to change the flex-direction in a media query:

@media screen and ( max-width: 500px ) {
    ul { flex-direction: column; }
    li { flex-basis: auto; }
}

jsfiddle demo

I would use media queries to change the flex-direction of the element to column if the items are too big for the window width. This will put the items of a list below each other.

HTML

<ul class="grid__row grid__row--sm">
    <li>1 small</li>
    <li>1 wide wide wide wide wide wide</li>
</ul>
<ul class="grid__row grid__row--sm">
    <li>2 medium medium</li>
    <li>2 small</li>
</ul>
<ul class="grid__row grid__row--md">
    <li>3 small</li>
    <li>3 wide wide wide wide wide wide</li>
    <li>3 medium medium</li>
</ul>

CSS

.grid__row {
    margin: auto;
    padding: 0;
    list-style-type: none;
    display: flex;
    flex-direction: column;
}

.grid__row li {
    background: green;
    color: white;
    margin: 1px;
    padding: 15px;
    display:flex;
    flex: 1;
}

@media (min-width: 480px) {
    .grid__row--sm {
        flex-direction: row;
    }
}

@media (min-width: 768px) {
    .grid__row--md {
        flex-direction: row;
    }
}

JSFiddle

You can't set flex-basis to auto or content because you want all boxes to be the same size, so flex-basis has to be 0 and flex-grow set to 1 , as you've correctly done. What you need to do now is set min-width (eg 200px ) on the flex items. Your mileage may vary, I believe safari (webkit has been doing a terribly job of keeping up since google went to blink) may be buggy with min-width on flex-items .

Alternatively you could just set the flex-basis to be the min-width property which should work, even in safari ( flex: 1 0 200px )

 ul { margin: auto; padding: 0; list-style-type: none; display: flex; flex-wrap: wrap; } li { background: green; margin: 1px; flex: 1 0 200px; } 
 <ul> <li>1 small</li> <li>1 wide wide wide wide wide wide</li> </ul> <ul> <li>2 medium medium</li> <li>2 small</li> </ul> <ul> <li>3 small</li> <li>3 wide wide wide wide wide wide</li> <li>3 medium medium</li> </ul> 

Thanks to Michael_B and Adam, I have found the solution to my problem.

flex-grow: 1;
flex-basis: 0;
min-width: fit-content;

The fit-content value of min-width is the key here. It is experimental (you may have to add a browser prefix), but it does exactly what I wanted: same width, with wrap !

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