Flexbox children shrink up to a certain point (but don't expand if they don't need to)

别说谁变了你拦得住时间么 提交于 2021-02-05 02:17:05

问题


I'm a having a bit of an issue here. I have a flexbox container with children of different sizes. Based on quantity and their content children might overflow the parent.

What I want is the children to shrink so they try to fit in the parent container. I did that by adding shrink and overflow properties to the children. So far so good.

.container > div {
  background-color: orange;
  padding: 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 1;
}

I end up with something like this:

Now I want them to shrink but up to a certain point (lets say 80px). I don't care if they end up overflowing the container but I don't want to render any smaller than 80px.

Of course, I added min-width: 80px to the children... but here is my problem. I want the children to shrink up to 80px but I don't want any of those that were smaller than 80px already (like Child1, Child4 and Child5) I don't want them to be enlarged by the min-width property (or, I want them to shrink further up to min-content)

In other words. I don't want this:

I would love to have something like this:

I tried doing something like min-width: min(min-content, 80px) but of course, didn't work.

Here is an small codepen with the issue: https://codepen.io/claudiofpen/pen/QWELVJO

.container {
  width: 300px;
  border: 1px solid black;
  display: flex;
  flex-direction: row;
  padding: 5px;
}
.container > div {
  background-color: orange;
  padding: 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 1;
  min-width: min-content;
}
.container > div:not(:last-child) {
  margin-right: 5px;
}

/* I don't want the following css classes, I cannot 
 tell in before hand which children are going to have 
 a larger content */
.container > div:nth-child(2), 
.container > div:nth-child(3) {
  min-width: 80px;
}
<div class="container">
  <div>Child 1</div>
  <div>Longer Child 2</div>
  <div>Longer Child 3</div>
  <div>Child 4</div>
  <div>Child 5</div>
</div>

回答1:


With an extra wrapper you can do it:

.container {
  width: 300px;
  border: 1px solid black;
  display: flex;
  flex-direction: row;
  padding: 5px;
}

.container > div {
  background-color: orange;
  padding: 5px;
  flex-shrink: 1;
  width: 80px;
}

.container > div > div {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  width: 100%;
}

.container > div:not(:last-child) {
  margin-right: 5px;
}
<div class="container">
  <div><div>Ch 1</div></div>
  <div><div>Longer Child 2</div></div>
  <div><div>Longer Child 3</div></div>
  <div><div>Child 4</div></div>
  <div><div>Child 5</div></div>
</div>



回答2:


Temani Afif's solution solves the problem of ensuring that a text element will not shrink below the specified width unless its intrinsic width is already below that width (in which case it uses its intrinsic width as the rendered width). But it does not work unless the sum of the specified widths of all the child elements exceeds the container's width.

So I tried giving each outer elements a flex-grow parameter, so that they would grow above their specified width, if the container had room. But I also give the outer elements a maximum width set to their intrinsic maximum content width, so they would never grow beyond the actual size of the text. Thus I added the following styles to the wrapping div.

 flex: 1 1 auto;
 max-width: max-content;

With that tweak I believe it solves the entire problem. The elements expand fully if there is room in the container. As we add more elements the longer elements start to shrink. But they never shrink below their specified width, so the container overflows once all inserted elements have shrunk down to that width. But elements that started with a shorter width never flex at all.

I have added an example below.

.container {
  width: 340px;
  border: 1px solid black;
  display: flex;
  flex-direction: row;
  padding: 5px;
}

.container>div {
  background-color: orange;
  padding: 5px;
  flex: 1 1 auto;
  width: 80px;
  max-width: max-content;
}

.container>div>div {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  width: 100%;
}

.container>div:not(:last-child) {
  margin-right: 5px;
}
<h5>When the items fit they expand to their intrinsic length</h5>
<div class="container">
  <div>
    <div>Medium length</div>
  </div>
  <div>
    <div>Tiny</div>
  </div>
  <div>
    <div>Longer text element</div>
  </div>
</div>
<h5>When the container limit is reached the longer elements start shrinking</h5>
<div class="container">
  <div>
    <div>Medium length</div>
  </div>
  <div>
    <div>Tiny</div>
  </div>
  <div>
    <div>Longer text element</div>
  </div>
  <div>
    <div>Filler</div>
  </div>
</div>
<h5>Adding more elements...</h5>
<div class="container">
  <div>
    <div>Medium length</div>
  </div>
  <div>
    <div>Tiny</div>
  </div>
  <div>
    <div>Longer text element</div>
  </div>
  <div>
    <div>Filler</div>
  </div>
  <div>
    <div>Filler</div>
  </div>
</div>
<h5>When there is no room it overflows<br> The tiny element stays at its intrinsic width, but the bigger elements stop shrinking at the specified width</h5>
<div class="container">
  <div>
    <div>Medium length</div>
  </div>
  <div>
    <div>Tiny</div>
  </div>
  <div>
    <div>Longer text element</div>
  </div>
  <div>
    <div>Filler</div>
  </div>
  <div>
    <div>Filler</div>
  </div>
  <div>
    <div>Filler</div>
  </div>
</div>



回答3:


Grid Solution

.container {
            width: 300px;
            border: 1px solid black;
            display: grid;
            grid-template-columns: max-content 80px 80px repeat(2,max-content);
            padding: 5px;
        }

You can use javascript to make the grid-template-column dynamic. Here is the jquery (javascript) solution using flex

.container {
            width: max-content;
            border: 1px solid black;
            display: flex;
            padding: 5px;
        }
$(".container > div").each(function(){
    ($(this).width() < 50) ?
        $(this).css('width','max-content') :
           $(this).css('flex','0 0 80px');
})

This is more dynamic than the grid solution. The only thing is that you will need to have a desired number in $(this).width() < 50 instead of fifty based on your content.



来源:https://stackoverflow.com/questions/64225800/flexbox-children-shrink-up-to-a-certain-point-but-dont-expand-if-they-dont-ne

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!