CSS 如何保持包裹的 flex-items 与前一行元素的宽度相同?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23274338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 02:19:24  来源:igfitidea点击:

How to keep wrapped flex-items the same width as the elements on the previous row?

cssflexbox

提问by midu

I have a <ul>that is a flex-box and a bunch of <li>s in it which are the flex-items.

我有一个<ul>flex-box 和一堆<li>s ,它们是弹性项目。

I am trying to get the <li>to have a flexible width, that stays between two sizes using min-width and max-width. It works great as long as they are on the same line. However, when they wrap, the <li>s on the new line use as much space as they can. Which means they are small on the first line, and big on the second line when there are just a few of them.

我试图获得<li>一个灵活的宽度,使用最小宽度和最大宽度保持在两个尺寸之间。只要它们在同一条线上,它就可以很好地工作。但是,当它们换<li>行时,新行上的s 会尽可能多地使用空间。这意味着它们在第一行很小,当只有几个时,它们在第二行很大。

Is there a way to tell flexbox to keep the items the width after wrapping, while keeping the flexible width?

有没有办法告诉 flexbox 在包装后保持项目的宽度,同时保持灵活的宽度?

wrapping demo:

包装演示:

enter image description here

在此处输入图片说明

My code looks like this:

我的代码如下所示:

<ul>
  <li>
    <figure>
      <img src="http://placekitten.com/g/250/250">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/100/100">
    </figure>
  </li>
  <!-- ... -->
</ul>

And the CSS:

和 CSS:

ul {
  display: flex;
  flex-wrap: wrap;
}

  li {
    min-width: 40px;
    max-width: 100px;
    flex: 1 0 0;
  }

Here's a live example on codepen with some extra comments, resize your window to see it wrap.

这是一个关于 codepen 的实时示例,带有一些额外的注释,调整窗口大小以查看它的包装。

回答by Merott

TL;DR

TL; 博士

This is not something I'd call a solutionper se, but it's a rather elegant workaround that only uses media queries, and more importantly no JavaScript!

这本身并不是我所说的解决方案,但它是一种相当优雅的解决方法,仅使用媒体查询,更重要的是不使用 JavaScript

Mixin (SCSS):

混合(SCSS):

@mixin flex-wrap-fix($flex-basis, $max-viewport-width: 2000px) {
  flex-grow: 1;
  flex-basis: $flex-basis;
  max-width: 100%;

  $multiplier: 1;
  $current-width: 0px;

  @while $current-width < $max-viewport-width {
    $current-width: $current-width + $flex-basis;
    $multiplier: $multiplier + 1;

    @media(min-width: $flex-basis * $multiplier) {
      max-width: percentage(1/$multiplier);
    }
  }
}

Usage:

用法:

Apply the mixin to your flex item:

将 mixin 应用到你的弹性项目:

.flex-item {
  @include flex-wrap-fix(100px)
}

Update:

更新:

The above mixin should do the trick, as long as you your flex container width matches your viewport size, as is the case in OP's example. Media queries won't help you otherwise, because they're always based on the viewport width. However, you could use the css-element-querieslibrary and its element queries instead of browser media queries. Here's a mixin that you can apply to the flex container:

上面的 mixin 应该可以解决问题,只要您的 flex 容器宽度与您的视口大小相匹配,就像 OP 示例中的情况一样。否则媒体查询对您没有帮助,因为它们始终基于视口宽度。但是,您可以使用css-element-queries库及其元素查询而不是浏览器媒体查询。这是一个可以应用于 flex容器的 mixin :

@mixin flex-container-wrap-items($flex-basis, $max-expected-width: 2000px) {
  display: flex;
  flex-wrap: wrap;

  > * {
    max-width: 100%;
    flex-grow: 1;
    flex-basis: $flex-basis;
  }

  $multiplier: 1;
  $current-width: 0px;

  @while $current-width < $max-expected-width {
    $current-width: $current-width + $flex-basis;
    $multiplier: $multiplier + 1;

    &[min-width~="#{$flex-basis * $multiplier}"] > * {
      max-width: percentage(1/$multiplier);
    }
  }
}


Explanation:

解释:

Let's say, as per the OP's example, we want each item to have a maximum width of 100px, so we know that for a browser width of 100pxwe can fit one item per row, and so on:

假设,根据 OP 的示例,我们希望每个项目的最大宽度为100px,因此我们知道对于浏览器宽度,100px我们可以每行容纳一个项目,依此类推:

| Viewport Width | Max Item Count Per Row | Item Width (min-max) |
|----------------|------------------------|----------------------|
| <= 100         | 1                      | 0px - 100px          |
| <= 200         | 2                      | 50px - 100px         |
| <= 300         | 3                      | 50px - 100px         |
| <= 400         | 4                      | 50px - 100px         |
| <= 500         | 5                      | 50px - 100px         |
| <= 600         | 6                      | 50px - 100px         |

We can write media queries to create the following rules:

我们可以编写媒体查询来创建以下规则:

| Viewport Width | Max Item Count Per Row | Item Max Width | Calculation |
|------------------------------------------------------------------------|
| <= 100px       | 1                      | 100%           | (100/1)     |
| <= 200px       | 2                      | 50%            | (100/2)     |
| <= 300px       | 3                      | 33.33333%      | (100/3)     |
| <= 400px       | 4                      | 25%            | (100/4)     |
| <= 500px       | 5                      | 20%            | (100/5)     |
| <= 600px       | 6                      | 16.66666%      | (100/6)     |

Like this:

像这样:

li {
  flex: 1 0 0
  max-width: 100%;
}

@media(min-width: 200px) {
  li { max-width: 50%; }
}

@media(min-width: 300px) {
  li { max-width: 33.33333%; }
}

@media(min-width: 400px) {
  li { max-width: 25%; }
}

@media(min-width: 500px) {
  li { max-width: 20%; }
}

@media(min-width: 600px) {
  li { max-width: 16.66666%; }
}

Of course, that's repetitive, but most likely you're using some sort of preprocessor, which can take care of the repetitiveness for you. That's precisely what the mixin in the above TL;DRsection does.

当然,这是重复的,但很可能您正在使用某种预处理器,它可以为您处理重复性。这正是上述TL;DR部分中的 mixin所做的。

All we have to do now is to specify 100pxas our flex-basis, and optionallythe maximum browser window width (defaults to 2000px) to create the media queries for:

我们现在要做的就是指定100px我们的flex-basis,以及可选的最大浏览器窗口宽度(默认为2000px)来创建媒体查询:

@include flex-wrap-fix(100px)

Example

例子

Finally, a forked version of the original CodePen example with the desired output, using the above mixin:

最后,原始 CodePen 示例的分叉版本具有所需的输出,使用上述 mixin:

http://codepen.io/anon/pen/aNVzoJ

http://codepen.io/anon/pen/aNVzoJ

demo of the solution

解决方案演示

回答by Pavelloz

I have been experimenting with your codepen and I set flex: 0 1 10%

我一直在试验你的代码笔,我设置了 flex: 0 1 10%

Of course you can set the flex-basis whatever you want, I just wanted to prove the point, that if you set flex basis and allow it to shrink, it will behave much nicer in this case.

当然,你可以设置任何你想要的 flex-basis,我只是想证明这一点,如果你设置 flex base 并允许它缩小,在这种情况下它会表现得更好。

I think this is what you needed. Here's the preview: http://codepen.io/anon/pen/bwqNEZ

我想这就是你所需要的。这是预览:http: //codepen.io/anon/pen/bwqNEZ

Cheers

干杯

回答by zer00ne

I think I got it...but it's hacky. The result is the 14 images each scaling from 100px wide down to 40px, even on multiple rows.

我想我明白了......但它很hacky。结果是 14 个图像,每个图像从 100 像素宽缩小到 40 像素,即使在多行上也是如此。

From 107px to 40px Width

从 107px 到 40px 宽度

  • Added a duplicate set of the 14 original <li>s and added them to the flex <ul>.
  • Next, the second set was rendered invisible:

    li:nth-of-type(n + 15) {
      visibility: hidden;
    }
    
  • In order to maintain uniform flexibility the following changes to each <li>:

    li {
      min-width: 40px;
      max-width: 10%;
      flex: 1 0 100px;
    }
    
  • 添加了 14 个原始<li>s的副本并将它们添加到 flex <ul>
  • 接下来,第二组变得不可见:

    li:nth-of-type(n + 15) {
      visibility: hidden;
    }
    
  • 为了保持统一的灵活性,对每个进行以下更改<li>

    li {
      min-width: 40px;
      max-width: 10%;
      flex: 1 0 100px;
    }
    

Please review the CodePen

请查看CodePen

and/or the Snippetin Full Page mode.

和/或整页模式下的代码段

ul {
  display: flex;
  flex-wrap: wrap;
  max-height: 258px;
}
li {
  min-width: 40px;
  max-width: 10%;
  flex: 1 0 100px;
}
ul,
li {
  margin: 0;
  padding: 0;
  list-style: none;
}
ul {
  background-color: tomato;
}
li {
  margin: 0.5em;
  background-color: darkgreen;
}
li img {
  width: 100%;
  opacity: 0.5;
}
li figure,
li img {
  margin: 0;
  padding: 0;
}
li:nth-of-type(n + 15) {
  visibility: hidden;
}
<ul>
  <li>
    <figure>
      <img src="http://placekitten.com/g/250/250">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/101/101">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/201/201">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/150/150">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/80/80">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/111/111">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/40/40">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/110/110">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/75/75">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/89/89">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/150/150">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/32/32">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/61/61">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/320/320">
    </figure>
  </li>



  <li>
    <figure>
      <img src="http://placekitten.com/g/250/250">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/101/101">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/201/201">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/150/150">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/80/80">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/111/111">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/40/40">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/110/110">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/75/75">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/89/89">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/150/150">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/32/32">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/61/61">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/320/320">
    </figure>
  </li>
</ul>

回答by Omer

Alternative - grid

替代 - 网格

its not the answer of what you want, but it nice to use:

它不是你想要的答案,但很好用:

display: grid
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr))

https://codepen.io/omergal/pen/povzJrz

https://codepen.io/omergal/pen/povzJrz

ul {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
}

li {
  min-width: 40px;
  max-width: 100px;
}

ul,
li {
  margin: 0;
  padding: 0;
  list-style: none;
}
ul {
  background-color: tomato;
}

li {
  margin: 0.5em;
  background-color: darkgreen;
}

img {
  width: 100%;
  opacity: 0.5;
}
figure,
img {
  margin: 0;
  padding: 0;
}
<ul>
      <li>
        <figure>
          <img src="http://placekitten.com/g/250/250">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/101/101">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/201/201">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/150/150">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/80/80">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/111/111">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/40/40">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/110/110">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/75/75">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/89/89">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/150/150">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/32/32">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/61/61">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/320/320">
        </figure>
      </li>
    </ul>

回答by lili2311

Setting the min-widthand max-widthas percentages has allowed all images to stay the same width when they break onto the next line. It is not ideal, but closer to what you are after?

min-width和设置max-width为百分比允许所有图像在下一行中断时保持相同的宽度。这并不理想,但更接近你所追求的?

li {
  min-width: 15%;
  max-width: 15%;  
}

回答by jdnz

I came here looking to solve the same problem for a flex box I have. I've since realised that this is now much easier with display: gridas detailed hereand here.

我来这里是为了解决我拥有的 flex 盒的相同问题。从那以后,我意识到这现在更容易了display: grid,详细信息在这里这里

回答by hobbeshunter

Its not working very well, but you can achieve something in this direction with columns.

它的效果不是很好,但是您可以使用列在这个方向上实现一些目标。

column-gap: 10px;
column-width: 150px;

https://codepen.io/hobbeshunter/pen/OgByNX

https://codepen.io/hobbeshunter/pen/OgByNX

回答by Miriam Salzer

This isn't perfect but worth try. http://codepen.io/anon/pen/MKmXpV

这并不完美,但值得一试。http://codepen.io/anon/pen/MKmXpV

The changes are

变化是

li
  width: 7.1428%
  flex: 0 0 auto

figure
  margin: 0 auto
  background-color: darkgreen
  min-width: 40px
  max-width: 100px
  • changed li flex to "0 0 auto" and the li width to a percentage based on the number of lis.
  • moved the min and max widths from the li to the figure
  • moved the green background to the figure and centered the figures in the lis
  • 将 li flex 更改为“0 0 auto”,将 li 宽度更改为基于 li 数量的百分比。
  • 将最小和最大宽度从 li 移动到图形
  • 将绿色背景移至图形并将图形居中放置在 lis 中

回答by Rob

My solution is not ideal, as it leans on JQuery: http://codepen.io/BigWillie/pen/WwyEXX

我的解决方案并不理想,因为它依赖于 JQuery:http: //codepen.io/BigWillie/pen/WwyEXX

CSS

CSS

ul {
  display: flex;
  flex-wrap: wrap;
}

li {
  min-width: 40px;
  max-width: 100px;
  flex: 1;
}

JavaScript

JavaScript

var eqRowFlexItem = function(elem) {
    var w;
    var $elem = $(elem);
    // Clear out max-width on elements
    $elem.css('max-width', '');
    w = $(elem).eq(0).width();
    $(elem).css('max-width', w);
}

eqRowFlexItem('li');

$(window).resize(function() {
    eqRowFlexItem('li');
});

I'm not entirely sure if it answers the problem. I found this post, as the title matched the problem I was having. I was after an effect whereby I would have a greater number of elements per row on larger screens - and fewer elements per row on smaller screens. In both cases, these elements also needed to scale to fit... across devices.

我不完全确定它是否能解决问题。我找到了这篇文章,因为标题与我遇到的问题相匹配。我追求的是一种效果,即在较大的屏幕上每行有更多的元素 - 在较小的屏幕上每行有更少的元素。在这两种情况下,这些元素还需要扩展以适应……跨设备。

However, those stray elements on the last row would always expand to fill the remaining space.

但是,最后一行上的那些杂散元素将始终扩展以填充剩余空间。

The JQuery gets the width of the first element - and applies it as a max-width to every element. The OP wanted the blocks to fall within a min-width / max-width rage. Setting the max-width in CSS seems to work. We clear the max-width off the element, so it defaults to the max-width in the CSS... then gets the actual width.

JQuery 获取第一个元素的宽度 - 并将其作为 max-width 应用于每个元素。OP 希望块落在最小宽度/最大宽度范围内。在 CSS 中设置 max-width 似乎有效。我们清除元素的最大宽度,因此它默认为 CSS 中的最大宽度...然后获取实际宽度。

回答by T.Hallam

I had the same issue, so I used a very tiny bit of Jquery to control the width of the boxes and make them all the same width even once they wrap.

我遇到了同样的问题,所以我使用了一点点 Jquery 来控制盒子的宽度,即使它们包装起来也使它们的宽度相同。

My demo is on CodePen Flex wrap, with equal width on new row

我的演示是在 CodePen Flex wrap 上,在新行上具有相等的宽度

function resize(){
  var colWidth;
  var screen = $(window).width(); 
  
  if(screen < 576){
    colWidth = Math.round(screen / 2) - 31;
    $(".item").width(colWidth);
  } 
  if(screen > 575 && screen < 768){
    colWidth = Math.round(screen / 3) - 31;
    $(".item").width(colWidth);
  } 
  else if (screen > 767 && screen < 992){
      colWidth = Math.round(screen / 4) -31;
      $(".item").width(colWidth);
  }
  else if (screen > 991 ){
      colWidth = Math.round(screen / 6) -31;
      $(".item").width(colWidth);
  }
}
  
window.onresize = function() {
  resize();
}

resize();
html,
body{
  padding:0;
  margin:0;
}
.flex-container {
  padding: 0;
  margin: 0;
  list-style: none;
  -ms-box-orient: horizontal;
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -moz-flex;
  display: -webkit-flex;
  display: flex;
  justify-content: left;
  background-color:#ddd;
}

.wrap    { 
  -webkit-flex-wrap: wrap;
  flex-wrap: wrap;
}  

.item {
  background: tomato;
  height: 100px;
  margin:0 15px;
  line-height: 100px;
  color: white;
  font-weight: bold;
  font-size: 2em;
  text-align: center;
  margin-top:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="flex-container wrap">
  <li class="item">1</li>
  <li class="item">2</li>
  <li class="item">3</li>
  <li class="item">4</li>
  <li class="item">5</li>
  <li class="item">6</li>
  <li class="item">7</li>
  <li class="item">8</li>
  <li class="item">9</li>
</ul>