【问题标题】:How to keep wrapped flex-items the same width as the elements on the previous row?如何保持包装的弹性项目与前一行元素的宽度相同?
【发布时间】:2014-06-10 01:25:32
【问题描述】:

我有一个<ul>,它是一个弹性盒子,里面有一堆<li>s,它们是弹性项目。

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

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

包装演示:

我的代码如下所示:

<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>

还有 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,调整您的窗口大小以使其包裹。

【问题讨论】:

标签: css flexbox


【解决方案1】:

这是 flexbox 的限制。您可以做的最好的事情是设置包装(增长)项目将遵守的最大宽度。为此,您需要 CSS Grid。

【讨论】:

    【解决方案2】:

    替代方案 - 网格

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

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

    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>

    【讨论】:

    • 在 MDN 上有一个完整的页面,Mastering Wrapping of Flex Items,专门用于包装弹性项目。 “在 flexbox 中没有方法可以告诉一行中的项目与上一行中的项目对齐——每条 flex 行就像一个新的 flex 容器。......如果你想要二维布局,那么你可能想要网格布局。 "
    【解决方案3】:

    如果布局是固定的,您可以简单地添加隐藏项并使用 css 断点来切换它们的可见性,用于发生环绕的像素。

    例如,在下面的场景中 .columned-list 有 3 个 .columned-list-item 元素,并且对于第 3 个 .columned-list 所在的像素-item 元素换行到下一行,我只是将第 4 个 .columned-list-item 元素 .hidden-item - 通常是不可见的 - 可见:

    .columned-list {
                display: flex;
                flex-wrap: wrap;
                margin-left: 35px;
    
    
                justify-content: flex-start;
    
    
    
                .hidden-item {
                    display: none !important;
    
                    @media only screen and (max-width: 1375px) {
                        flex: 1 0 auto !important;
                        min-width: 410px !important;
                        width: 30% !important;
                        margin: 0 37px 37px 0 !important;
                        max-width: 100% !important;
                        display: flex !important;
                        background-color: #fff !important;
                    }
    
                    @media only screen and (max-width: 928px) {
                        display: none !important;
                    }
                }
    
                .columned-list-item {
                    flex: 1 0 auto;
                    min-width: 410px;
                    min-height: 1px !important; // <3 IE.
                    width: 30%;
                    margin: 0 37px 37px 0;
                    max-width: 100%;
                    display: flex;
                    flex-direction: column;
                    align-items: center;
                    color: #676562;
                    background-color: #f2f3f5;
    
                    a:nth-of-type(1) {
                        position: relative;
                        min-height: 84px;
                        width: 100%;
    
                        img {
                            width: 100%;
                            height: auto;
                        }
    
                        div {
                            min-height: 88px;
                            max-width: 203px;
                            padding: 0 15px;
                            top: 50%;
                            transform: translateY(-50%);
                            position: absolute;
                            display: flex;
                            justify-content: center;
                            align-items: center;
    
                            background-color: #fff;
                            opacity: 0.6;
                            span {
                                height: 55px;
                                font-family: 'Trade Gothic Next LT W04 Rg', sans-serif;
                                font-size: 28px;
                                font-weight: bold;
                                font-stretch: normal;
                                font-style: normal;
                                line-height: 1;
                                letter-spacing: 0.7px;
                                text-align: left;
                                color: #676562;
                            }
    
                        }
    
                    }
    
                    a:nth-of-type(2) {
    
                        padding: 10px 35px;
                        display: flex;
                        flex-direction: column;
                        min-height: 161px;
                        max-width: 390px;
    
                        strong {
                            font-family: 'Trade Gothic Next LT W04 Bold', sans-serif;
                            font-weight: bold;
                            text-align: center;
                        }
                        span {
    
                            font-family: 'Trade Gothic Next LT W04 Light', sans-serif;
                            font-size: 15px;
                            font-weight: normal;
                            font-stretch: normal;
                            font-style: normal;
                            line-height: 1.4;
                            letter-spacing: normal;
                            text-align: center;
                            color: #676562;
    
                        }
                    }
    
                    .buttons-block {
                        display: flex;
                        justify-content: space-between;
                        align-items: center;
                        width: 298px;
                        max-width: 100%;
                        margin: 10px 0 23px 0;
    
                        .button-a {
                            width: 114px;
                            height: 22px;
                            min-height: 1px;
                            box-shadow: 0px 1px 0 0 rgba(0, 0, 0, 0.16);
                            background-color: #f28d4e;
                            display: flex;
                            justify-content: center;
                            align-items: center;
    
                            span {
                                font-family: 'Trade Gothic Next LT W04 Rg', sans-serif;
                                font-size: 15px;
                                font-weight: bold;
                                font-stretch: normal;
                                font-style: normal;
                                line-height: 1.4;
                                letter-spacing: normal;
                                text-align: center;
                                color: #ffffff;
                            }
                        }
    
                        .button-b {
                            margin-bottom: 0;
                            padding: 0;
                        }
    
                    }
    
                    @media only screen and (max-width: 760px) {
                        margin: 0 0 20px 0;
                    }
                    @media only screen and (max-width: 410px) {
    
                        min-width: auto;
                        width: 100%;
                    }
                }
    
                @media only screen and (max-width: 760px) {
                    display: flex !important;
                    flex-direction: column;
                    align-items: center;
                    margin-left: 0;
                    padding-top: 10px;
                }
    
    
            }
    

    【讨论】:

      【解决方案4】:

      我来这里是为了解决我拥有的弹性盒子的同样问题。我已经意识到现在使用display: grid 更容易做到这一点,详细的here 和here。

      【讨论】:

        【解决方案5】:

        对于 Stylus,你可以使用这个 mixin:https://codepen.io/anon/pen/Epjwjq

        
           flex-wrap-fix($basis, $max) {
             flex-grow: 1
             flex-basis: $basis
             max-width: 100%
        
             $multiplier = ceil($max / $basis)
        
             for i in (1..$multiplier) {
               @media(min-width: ($basis * i)) {
                 max-width: percentage(1/i)
               }
             }
           }
        

        【讨论】:

          【解决方案6】:

          TL;DR

          这不是我称之为解决方案本身的东西,但它是一个相当优雅的解决方法,只使用媒体查询,更重要的是没有 JavaScript! p>

          混合(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);
              }
            }
          }
          

          用法:

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

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

          更新:

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

          说明:

          假设,根据 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         |
          

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

          | 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)     |
          

          像这样:

          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%; }
          }
          

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

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

          @include flex-wrap-fix(100px)
          

          示例

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

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

          【讨论】:

            【解决方案7】:

            它工作得不是很好,但你可以通过列在这个方向上取得一些成就。

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

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

            【讨论】:

            • 知道了,谢谢。为什么说效果不好?您指的是浏览器/功能支持吗?
            • 嗯,这并不是 midu 想要的,因为它会重新排列列而不是行中的元素。
            • 我注意到了,很奇怪。
            【解决方案8】:

            我也遇到了同样的问题,所以我用了一点点 Jquery 来控制盒子的宽度,并让它们在包装后都保持相同的宽度。

            我的演示在 CodePen Flex wrap, with equal width on new row

            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>

            【讨论】:

              【解决方案9】:

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

              当然,你可以随意设置 flex-basis,我只是想证明一点,如果你设置了 flex-basis 并允许它收缩,在这种情况下它会表现得更好。

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

              干杯

              【讨论】:

              • 谢谢!这应该是公认的答案,因为在不同的视口上下文中重用组件时,媒体查询会造成问题。
              【解决方案10】:

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

              CSS

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

              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');
              });
              

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

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

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

              【讨论】:

                【解决方案11】:

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

                • 添加了 14 个原始 &lt;li&gt;s 的重复集,并将它们添加到 flex &lt;ul&gt;。
                • 接下来,第二组被渲染为不可见:

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

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

                请查看CodePen

                和/或全页模式下的片段。

                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>

                【讨论】:

                  【解决方案12】:

                  将min-width 和max-width 设置为百分比可以让所有图像在进入下一行时保持相同的宽度。不理想,但更接近你的追求?

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

                  【讨论】:

                    【解决方案13】:

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

                    变化是

                    li
                      width: 7.1428%
                      flex: 0 0 auto
                    
                    figure
                      margin: 0 auto
                      background-color: darkgreen
                      min-width: 40px
                      max-width: 100px
                    
                    • 将 li flex 更改为“0 0 auto”,并将 li 宽度更改为基于百分比 lis 的数量。
                    • 将最小和最大宽度从 li 移到了图中
                    • 将绿色背景移至图形并将图形居中 利斯

                    【讨论】:

                      【解决方案14】:

                      使用max-width: 40px 而不是max-width: 100px

                      【讨论】:

                      • 这并不能解决@midu 的问题,即尝试保持40px 和100px 的灵活宽度。
                      猜你喜欢
                      • 2015-12-26
                      • 2021-12-17
                      • 1970-01-01
                      • 2018-02-23
                      • 2017-11-04
                      • 2015-09-18
                      • 2014-05-29
                      • 1970-01-01
                      • 2017-11-30
                      相关资源
                      最近更新 更多