是否可以针对 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>
【问题讨论】:
很难说没有任何代码可以继续。 嗯,这是一个理论问题,如果真的需要,我会设置一个小提琴,即使它只是ul
和 li
s。
行是均匀的还是不均匀的?如果每行的项目数量一致,您可以使用: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 布局中每行的第一个和最后一个元素?的主要内容,如果未能解决你的问题,请参考以下文章