Html 如何在最后一行左对齐的情况下将包装 flex 项目显示为间隔?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34331102/
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-29 18:39:59  来源:igfitidea点击:

How to display wrapping flex items as space-between with last row aligned left?

htmlcssflexbox

提问by Guy Benron

I have a fixed-width container into which several variable-width elements must appear in a row, which can spill over into additional rows as necessary.

我有一个固定宽度的容器,其中必须连续出现几个宽度可变的元素,这些元素可以根据需要溢出到其他行中。

However, the beginning of each element must be aligned with the one on top of it, so in ASCII art it would look like so (say, padding of 1):

但是,每个元素的开头必须与它上面的元素对齐,因此在 ASCII 艺术中它看起来像这样(例如,填充为 1):

    /----------------------------------\
    |                                  |
    | # One    # Two   # Three  # Four |
    | # Five   # Six                   |
    |                                  |
    \----------------------------------/

In other words:

换句话说:

  • The first element of every row must be left-aligned
  • The last element of every row (except for the final row) must be right-aligned
  • Every element must be left-aligned to the element above it
  • 每行的第一个元素必须左对齐
  • 每行的最后一个元素(最后一行除外)必须右对齐
  • 每个元素都必须与其上方的元素左对齐

I'm trying to use flexbox for this without success.

我正在尝试为此使用 flexbox,但没有成功。

Thisis the best I've come so far, using flex-wrap: wrapfor the container and flex-grow: 1for the elements.

是我迄今为止最好的,flex-wrap: wrap用于容器和flex-grow: 1元素。

Problem is that the last row fills out to the edge.

问题是最后一行填充到边缘。

justify-content: flex-start; // this does nothing

If I take away flow-grow: 1then the elements aren't distributed equally. I also tried fiddling around with last-of-typeon the elements but it's also not enough.

如果我拿走,flow-grow: 1那么元素不会平均分布。我也尝试摆弄last-of-type元素,但这还不够。

Is this even possible with flexbox, or am I going about it the wrong way?

这甚至可能与flexbox,还是我以错误的方式进行?

采纳答案by Guy Benron

After trying the suggestions here (thanks!) and searching the web long and wide, I've reached the conclusion that this is simply not possible with flexbox. Any by that I mean that others have reached this conclusion while I stubbornly tried to make it work anyway, until finally giving up and accepting the wisdom of wiser people.

在尝试了这里的建议(谢谢!)并在网上广泛搜索之后,我得出的结论是,这对于 flexbox 来说根本不可能。我的意思是其他人已经得出了这个结论,而我仍然顽固地试图让它发挥作用,直到最终放弃并接受更聪明的人的智慧。

There are a couple of links I came across that might explain it better, or different aspects of the requirements, so I'm posting them here for... posterity.

我遇到了一些链接,它们可能会更好地解释它,或者要求的不同方面,所以我将它们张贴在这里是为了......后代。

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

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

http://fourkitchens.com/blog/article/responsive-multi-column-lists-flexbox

http://fourkitchens.com/blog/article/responsive-multi-column-lists-flexbox

回答by Mintenker

I know I am kind of late, but I have been looking for solution for this in past hour or so, and I think I sort of figured it out. Put empty divon the end of your container, and set flex-grow: 1to it, and nothing else. Also set justify-content: space-betweenon container, and don't use flex-growon other items. This will always make last line align left because this div will stretch through all remaining space.

我知道我有点晚了,但我在过去一个小时左右一直在寻找解决方案,我想我已经想通了。把空的div放在你的容器的末端,然后放在flex-grow: 1上面,没有别的。也设置justify-content: space-between在容器上,不要用于flex-grow其他物品。这将始终使最后一行向左对齐,因为此 div 将穿过所有剩余空间。

However the problem of this is that it ALWAYS makes last line align left - even if it is the only line, which makes this solution unusable for me, but it might be usable for someone who can expect more than one line of items.

然而,这样做的问题是它总是使最后一行左对齐 - 即使它是唯一的一行,这使得这个解决方案对我来说不可用,但它可能适用于可以期待多行项目的人。

回答by MikeyP

I was able to achieve the desired result with a combination of positive and negative margins.

我能够通过正负边距的组合实现预期的结果。

If each element in the container defines a margin to create a space between them:

如果容器中的每个元素都定义了一个边距以在它们之间创建一个空间:

.container .element {
   flex: 1;
   margin: 0px 5px;
}

recover the pixels from the edges of each row in the container with a negative margin of the same amount:

使用相同数量的负边距从容器中每行的边缘恢复像素:

.container {
   display: flex;
   flex-direction: row;
   flex-wrap: wrap;
   margin: 0px -5px;
}

This should result in 10px between each element in the row with the first and last of each row at the edge of the container.

这应该导致行中的每个元素与容器边缘的每行的第一个和最后一个元素之间有 10px 的间隔。

回答by lakesare

If the width of your items is fixed, you can add several empty divs to the end of your list of items:

如果您的项目的宽度是固定的,您可以在项目列表的末尾添加几个空的 div:

<div class="item">meaningful content</div>
<div class="item">meaningful content</div>
<div class="item">meaningful content</div>

<div class="empty-div"></div>
<div class="empty-div"></div>
<div class="empty-div"></div>

and then:

进而:

.item, .empty-div{ width: 150px; } // make them the same width

Works perfectly well.

工作得很好。

回答by Moritz Friedrich

I just stumbled across the same problem and came up with another solution. I can't decide whether it feels kind of dirty or elegant, but decide for yourself.

我只是偶然发现了同样的问题,并想出了另一种解决方案。我无法决定它是肮脏的还是优雅的,但你自己决定。

Add as many empty divs as your maximum number of items per row to the container, assign them the same class as row items but remove any margin or padding from them (basically anything which gives them a height). That'll result in the row behaving as expected because after the last row item, there'll always be enough invisible "spacers" to pad the row. Those being wrapped to the next row have no height, so they shouldn't affect the rest of your page.

将与div每行最大项目数一样多的空s添加到容器中,为它们分配与行项目相同的类,但从中删除任何边距或填充(基本上是任何赋予它们高度的东西)。这将导致该行按预期运行,因为在最后一行项目之后,总会有足够的不可见“间隔”来填充该行。被包装到下一行的那些没有高度,所以它们不应该影响页面的其余部分。

Example here: https://jsfiddle.net/amknwjmj/

这里的例子:https: //jsfiddle.net/amknwjmj/

.products {
  display:         flex;
  flex-wrap:       wrap;
  justify-content: space-between;
}

.product {
    
  /* set top and bottom margin only, as left and right
     will be handled by space-between */
  margin: 0.25rem 0;

  /* account your desired margin two times and substract
     it from the base width of the row item */
  flex-basis: calc(25% - (0.25rem * 2));
}

.product.spacer {
      
  /* remove all properties increasing the element height 
     from the spacers to avoid them being visible */
  margin:  0;
  padding: 0;
  height:  initial;
}

/* start demo styles (purely eye-candy not required for this to work) */
* {
  box-sizing:  border-box;
  font-family: sans-serif;
}

.products {
  padding: .25rem .5rem;
  background: powderblue;
}

.product {
  height:      75px;
  line-height: 75px;
  padding:     .25rem;
  text-align:  center;
  background:  steelblue;
  color:       #fff;
}  
  
.product.spacer {
  background: none;

  /* of course, spacers should NOT have a border
     but they are helpful to illstrate what's going on. */
  border: 1px dashed gray;
}
/* end demo styles */
<div class="products">
  <article id="product-1" class="product">P1</article>
  <article id="product-2" class="product">P2</article>
  <article id="product-3" class="product">P3</article>
  <article id="product-4" class="product">P4</article>

  <article id="product-5" class="product">P5</article>
  <div class="product spacer"></div>
  <div class="product spacer"></div>
  <div class="product spacer"></div>

  <div class="product spacer"></div>
</div>

回答by Kristjan Liiva

There is no easy way to do this with flexbox. But if you are willing to sacrifice IE then you can do it with css grid, add this to the container:

使用 flexbox 没有简单的方法可以做到这一点。但是如果你愿意牺牲 IE 那么你可以用 css 来做grid,把它添加到容器中:

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

And if you want to have some space between the elements then add

如果你想在元素之间有一些空间然后添加

grid-gap: 10px;

回答by tFranz

You could try it with a fixed-with-pseudo-element:

你可以用一个fixed-with-pseudo-element来试试:

.container {
 display:flex;
 justify-content:space-between;
}
.container:after {
  content: '';
  flex-grow: 0;
  width: 25%;
}
.container .element {
  width: 25%;
}

回答by cbcaio

so, you have a container and some stuff inside?

所以,你有一个容器和里面的一些东西?

<div class="container">
  <span>msg1</span>
  <span>msg1</span>
  <span>msg1</span>
  <span>msg1</span>
  <span>msg1</span>
</div>

This is how it works, when you declare display: flexfor your container all of its direct children will become flex too, with some default config (align-items:strech).

这就是它的工作原理,当您display: flex为容器声明时,它的所有直接子项也将变为 flex,并带有一些默认配置 ( align-items:strech)。

I guess you already got that, so, maybe you can try using justify-content: space-betweenwhich will align your items in the row leaving them equally spaced plus flex-basis: 25%(to certify that there will be always 4 items in a row, change de % as you wish) that is supposed to work for all your lines except the last one. For the last one you can use a css selector (like last-child) and set its property to flex-grow: 0/ flex-shrink:0(solving one of your problems, if you used flex: 1 1 25%instead of flex-basis) and also align-self: flex-startor whatever you like

我想你已经明白了,所以,也许你可以尝试使用justify-content: space-betweenwhich 将你的项目在行中对齐,使它们等距加上flex-basis: 25%(以证明总是有 4 个项目在一行中,根据需要更改 de %)即应该适用于除最后一行之外的所有行。对于最后一个,您可以使用 css 选择器(如last-child)并将其属性设置为flex-grow: 0/ flex-shrink:0(解决您的问题之一,如果您使用flex: 1 1 25%代替flex-basis)以及align-self: flex-start您喜欢的任何内容

回答by Jean-Charles Lateltin

I was facing the same issue and in fact it's really simple. No need to put some SCSS and or jQuery.

我面临着同样的问题,实际上这很简单。无需放置一些 SCSS 和或 jQuery。

You just need to specify a maximum number of "square", and make a modulo to know if that match with your maxNumber. If its not, you just have to define a quick function that increment your number until that modulo return 0.

您只需要指定“正方形”的最大数量,并进行取模以了解它是否与您的 maxNumber 匹配。如果不是,您只需要定义一个快速函数来增加您的数字,直到该模返回 0。

When you have your number you just have to loop your html. For me I was coding on ReactNative:

当你有你的号码时,你只需要循环你的 html。对我来说,我在 ReactNative 上编码:

const RenderInvisibleSquare = (nb) => {
 let tab = [];
 let i = 1;
 for (; (nb + i) % 3 !== 0; i++) {}
 for (let n = 0; n < i; n++) {
  tab.push(<View style={{ width: 120, height: 120, backgroundColor: 'red' }}/>);
 }
 return tab;
};


<ScrollView>
  {
    data.map(item => (
      <View>
        <View style={{ marginVertical: 5 }}>
          <Text style={{ textAlign: 'center', color: '#7E8BF5' }}>{item.title}</Text>
        </View>
        <View style={{ flex: 1, flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-around', flexDirection: 'row' }}>
          {
            item.data.map(elem => (
              <View style={{ width: 120, height: 120, marginBottom: 10, backgroundColor: 'red' }} />
            ))
          }
          { item.data.length % 3 !== 0 && RenderInvisibleSquare(item.data.length)}
        </View>
      </View>
    ))
  }
</ScrollView>

If you dont want content (backgroundColor: 'red') in my case you juste have to make it 'transparent'.

如果你不想要内容 (backgroundColor: 'red') 在我的情况下你必须让它“透明”。