是否可以针对 flex 布局中每行的第一个和最后一个元素?

Posted

技术标签:

【中文标题】是否可以针对 flex 布局中每行的第一个和最后一个元素?【英文标题】:Is it possible to target the first and the last element per row in a flex layout? 【发布时间】:2016-12-22 02:32:59 【问题描述】:

给定 flex 布局中的缩略图列表,如果 flex 容器具有可变宽度,是否可以仅使用 CSS 定位每行的第一个和最后一个元素?

.thumbnails 
  display: flex;
  margin: 0;
  padding: 0;
  list-style-type: none;
  flex-flow: row wrap;

.thumbnail 
  width: 250px;
  height: 250px;
  margin: 5px;
  background: #ccc;
  border: 1px solid #000;
<ul class="thumbnails">
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
</ul>

【问题讨论】:

很难说没有任何代码可以继续。 嗯,这是一个理论问题,如果真的需要,我会设置一个小提琴,即使它只是 ullis。 行是均匀的还是不均匀的?如果每行的项目数量一致,您可以使用:nth-child 这里有一个小提琴:jsfiddle.net/Lmc2e6wt/1 容器的宽度是可变的,所以它越宽,一行中的元素就越多。我需要的是针对每行的第一个和最后一个元素。 这样的定位在 CSS 中是不可能的。如果您使用媒体查询,并且项目是固定宽度的,您可以根据您设置的范围定位一行中的第一个和最后一个元素。更多细节和例子在这里:***.com/a/32811002/3597276 【参考方案1】:

Flexbox 很棒,但有时很难处理..

这里你有一个更新版本的 JQuery 脚本,它使用 flex 布局来定位每行的第一个孩子和最后一个孩子:

// Call the function anytime needed, by default on loading and resizing window, see below
function flexboxRowLastChild()

    $(document).ready(function()
    
        //For each element with class="flexbox-wrapper"
        $('.flexbox-wrapper').each(function() 
        
            //Reset at every function call
            $(this).children('.flexbox-row-first-child').removeClass('flexbox-row-first-child');
            $(this).children('.flexbox-row-last-child').removeClass('flexbox-row-last-child');
            
            //Set :first-child and :last-child (or use css pseudo-element instead)
            $(this).children().eq(0).addClass('flexbox-row-first-child');
            $(this).children().eq($(this).children().length - 1).addClass('flexbox-row-last-child');
            
            var rowWidth = $(this).children().eq(0).outerWidth(true);
            
            //For counting number of row if needed
            var nbrRow = 1;
            
            for (var i = 0; i < $(this).children().length; i++) 
                if (rowWidth <= $(this).width()) 
                //Sum of every children width (with margin) while it's less than the flexbox-wrapper width 
                    var rowWidth = rowWidth + $(this).children().eq(i+1).outerWidth(true);
                 else 
                //Set the flexbox-row-first-child and flexbox-row-last-child classes and begin to check for a new row
                    $(this).children().eq(i-1).addClass('flexbox-row-last-child');
                    $(this).children().eq(i).addClass('flexbox-row-first-child');
                    var nbrRow = nbrRow + 1;
                    var rowWidth = $(this).children().eq(i).outerWidth(true) + $(this).children().eq(i+1).outerWidth(true);
                
                
            
            
        );
        
    );



$(document).ready(function()

    // Call the function on window load
    flexboxRowLastChild();

    // Call the function on window resize
    $(window).resize(function()
        flexboxRowLastChild();
    );

);
.flexbox-wrapper 
  display: flex;
  margin: 0;
  padding: 0;
  list-style-type: none;
  flex-flow: row wrap;

.thumbnail 
  width: 100px;
  height: 100px;
  margin: 5px;
  background: #ccc;
  border: 1px solid #000;


.thumbnail.flexbox-row-first-child 
  background: #000;


.thumbnail.flexbox-row-last-child 
  background: #444;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<ul class="flexbox-wrapper">
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
</ul>

【讨论】:

【参考方案2】:

您可以像我在这里所做的那样使用 javascript 完成此操作:

var wrapper = document.getElementById('wrapper');
var thumbnails = document.getElementsByClassName('thumbnail');

var thumbnailsPerLine = Math.floor(wrapper.offsetWidth / 262); // 262px = complete width of thumbnail including margin and border.

for(var i = 0; i < thumbnails.length; i++)
  // add 'first-class' to first element.
  if(i === 0) thumbnails[i].classList.add('first');
  
  // check if its the last of the row, then add 'last-class'
  if((i+1) % thumbnailsPerLine === 0) thumbnails[i].classList.add('last');
  
  // check if its the first of a new row, then add 'first-class'
  if(i % thumbnailsPerLine === 0) thumbnails[i].classList.add('first');
  
  // check if its the last thumbail of all and check if its not the first of its row, then add 'last-class'
  if((i+1 === thumbnails.length) && !thumbnails[i].classList.contains('first')) thumbnails[i].classList.add('last');
.thumbnails 
  display: flex;
  margin: 0;
  padding: 0;
  list-style-type: none;
  flex-flow: row wrap;

.thumbnail 
  width: 250px;
  height: 250px;
  margin: 5px;
  background: #ccc;
  border: 1px solid #000;

.first 
  background: #000;

.last 
  background: #444;
<ul class="thumbnails" id="wrapper">
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
  <li class="thumbnail"></li>
</ul>

【讨论】:

【参考方案3】:

我会为 flex 元素设置一个宽度(比如 25% 以连续显示 4 个或 33.333% 以显示 3 个)。这样,您总是可以知道每行有多少项目。在一行 3 中,您可以使用 ... element:nth-child(3n) 定位最后一个元素,使用 element(3n-2) 定位第一个元素。同样适用于每行任意数量的项目。 如果最后一行包含的数字少于您的想法,您可能会看到一些奇怪的东西。例如,如果您将 flex 元素设置为 33.333% 宽度,并且最后一行仅包含 2 个元素,则样式可能会破坏,具体取决于您如何证明 flexbox 的合理性。您始终可以通过应用 margin-right: auto 将最后一个元素向左推。

【讨论】:

以上是关于是否可以针对 flex 布局中每行的第一个和最后一个元素?的主要内容,如果未能解决你的问题,请参考以下文章

Flex:选择包裹的flex中每一行的第一个和最后一个项目

flex布局space-between,最后一行左对齐

flex布局space-between,最后一行左对齐

数组元素布局为自适应+不固定每行个数+响应式

flex 布局解决最后一个布局问题

flex布局最后一行左对齐的处理