【问题标题】:How to display wrapping flex items as space-between with last row aligned left?如何将包装弹性项目显示为最后一行左对齐的空格?
【发布时间】:2016-03-23 17:10:28
【问题描述】:

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

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

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

换句话说:

  • 每行的第一个元素必须左对齐
  • 每行的最后一个元素(最后一行除外)必须右对齐
  • 每个元素都必须与其上方的元素左对齐

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

This 是我目前为止最好的,使用flex-wrap: wrap 作为容器,flex-grow: 1 作为元素。

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

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

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

flexbox 甚至可以做到这一点,还是我走错了路?

【问题讨论】:

标签: html css flexbox


【解决方案1】:

CSS Flex 4 列总是从左边开始。我看不到为什么这不可能?如果列应该等于,这为我们工作使用calc() 和相对单位:

/* parent */

.ua-flex {
    display: flex;
    flex-wrap: wrap;
    justify-content: start;
}

/* children */

.ua-flex > * {
    flex: 0 0 calc(25% - 1em);
    margin: 1em 0 0 0;
}
.ua-flex > :not(:nth-child(4n+4)) {
    margin-right: 1.333333em;
}

我在这里遗漏了什么吗?它的所有关于数学,在这种情况下减去 calc() 1em,在 4 列中的 3 列上给出 3 个间隙 1.333em 的空间,margin-right,0.5em 减去 calc() 应该给出 0.666em 的间隙,margin-right 在 3共 4 列。

希望这可以有用...

【讨论】:

  • 此解决方案有效,没有填充或网格。谢谢!
  • 不错!有效,我只需要将 .ua-flex > :not(:nth-child(4n+4) 的语法更改为 .ua-flex:not(:nth-child(4n+4) 即可使该规则也起作用。谢谢!
【解决方案2】:

您可以通过执行以下操作在除 flex-wrap 行中的最后一项之外的每个项上指定 margin-right

.item:not(:nth-child(4n)) {
  margin-right: 20px;
}

【讨论】:

    【解决方案3】:

    在许多情况下都可以使用的一种解决方案是将padding 应用于项目。然后你可以使用flex-start,并在卡片之间设置间距。

    例如

    .container {
      display: flex;
      justify-content: center;
    }
    
    .parent {
      width: 420px;
      display: flex;
      flex-wrap: wrap;
      flex-direction: row;
      justify-content: flex-start;
    }
    
    .child {
      flex: 0 30%;
      min-width: 100px;
      padding-left: 10px;
      margin-bottom: 10px;
    }
    
    .child-content {
      background-color: yellow;
      border: 1px solid black;
      height: 100px;
    }
    <div class="container">
      <div class="parent">
        <div class="child">
          <div class="child-content">
            Box
          </div>
        </div>
    
        <div class="child">
          <div class="child-content">
            Box
          </div>
        </div>
    
        <div class="child">
          <div class="child-content">
            Box
          </div>
        </div>
        
            <div class="child">
          <div class="child-content">
            Box
          </div>
        </div>
        
            <div class="child">
          <div class="child-content">
            Box
          </div>
        </div>
      </div>
    </div>

    【讨论】:

      【解决方案4】:

      我也遇到过同样的问题,其实很简单。不需要放一些 SCSS 和/或 jQuery。

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

      当你有你的号码时,你只需要循环你的 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>
      

      如果您不想要内容(背景颜色:“红色”),在我的情况下,您只需将其设为“透明”即可。

      【讨论】:

      • "不需要使用 SCSS 或 [jQuery]" 但你需要使用 React?对于 CSS 问题并不是很有用...
      【解决方案5】:

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

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

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

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

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

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

      【讨论】:

      • 这是一个很好的解决方案,可以在换行时在工作之间留出空间。然而,这个答案最终并没有回答这个问题。海报正在寻找与其他行相同大小的框左对齐的最后一行。
      【解决方案6】:

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

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

      如果你想在元素之间有一些空间,那么添加

      grid-gap: 10px;
      

      【讨论】:

        【解决方案7】:

        我只是偶然发现了同样的问题并想出了另一个解决方案。我无法决定它是否感觉有点脏或优雅,但你自己决定。

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

        这里的例子: 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>

        【讨论】:

          【解决方案8】:

          您可以尝试使用带有伪元素的固定:

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

          【讨论】:

            【解决方案9】:

            如果您的项目的宽度是固定的,您可以在项目列表的末尾添加几个空 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>
            

            然后:

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

            效果很好。

            【讨论】:

            • 没有完全回答这个问题,但它回答了我的问题:)
            【解决方案10】:

            我知道我有点迟到了,但我在过去一个小时左右一直在寻找解决方案,我想我有点想通了。将空的div 放在容器的末尾,并将flex-grow: 1 设置为它,仅此而已。还要在容器上设置justify-content: space-between,不要在其他项目上使用flex-grow。这将始终使最后一行左对齐,因为此 div 将延伸到所有剩余空间。

            但是问题在于它总是使最后一行左对齐 - 即使它是唯一的一行,这使得这个解决方案对我来说不可用,但它可能对那些可以期待不止一行项目的人有用.

            【讨论】:

            • 这是个好主意,但不幸的是,这种方法的间距不是行与行之间的 equel :'(
            【解决方案11】:

            在尝试了这里的建议(谢谢!)并在网上长时间搜索后,我得出的结论是,使用 flexbox 根本不可能做到这一点。我的意思是其他人已经得出了这个结论,而我固执地试图让它发挥作用,直到最终放弃并接受更聪明的人的智慧。

            我遇到的几个链接可能会更好地解释它,或者要求的不同方面,所以我将它们发布在这里......后代。

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

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

            【讨论】:

            • Jonas Lundman 发布的解决方案似乎可以解决问题。
            【解决方案12】:

            那么,你有一个容器和里面的一些东西吗?

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

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

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

            【讨论】:

            • 有几个问题.. 我希望第一行表现得像justify-content: space-between,最后一行表现得像justify-content: flex-start。此外,最后一个元素不会根据您的建议缩小或增长,但它可能不会单独出现在该行中,并且不会阻止其他元素缩小或增长(可能与第一点有关)。
            • 我不知道有多少项目,也不知道它们的宽度——它是动态加载的。
            • 您将需要一种方法来确定哪些元素在您的最后一行中。您可以尝试嵌套的 flexbox 并将一些逻辑应用于您正在使用的任何东西来动态加载您的东西。或者您可以使用常规引导列(也可以正常工作)和 flexbox 仅用于对齐内部内容,抱歉,我无法提供更多帮助。
            • Columns + inner flex 可能是要走的路,我会试一试。谢谢:)
            猜你喜欢
            • 2018-01-29
            • 2019-06-24
            • 1970-01-01
            • 1970-01-01
            • 2021-04-19
            • 2018-01-26
            • 2017-05-29
            • 2019-01-05
            • 2017-10-22
            相关资源
            最近更新 更多