在一个宽度100%,也就是宽度不固定的容器中,里面有横向排列并且会换行的列表项,列表项的宽度固定,所以每行列表项的个数随着容器的宽度变化:

<div class="box">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    ....
</div>


.box{
    display: flex;
    flex-wrap: wrap;
}
.item{
    width: 200px;
    height: 300px;
    margin-bottom: 20px;
}

在列表项不超过一行的时候表现很正常,但是在出现换行的情况下,每行最后可能会出现比较大的空白,这是因为虽然这行剩余的空间放不下一个.item了,但可能只比.item的宽度小一点点:

1.png

我们的目的是,让列表两端对齐,每个项的边距一样大,最后一行如果有空缺,那么就左对齐:

3.png

如果给.box设置下面的样式会怎样呢:

.box {
    ......
    justify-content: space-between;
    ......

如果一共5个.item,每行显示3个.item,结果会像这样:

2.png

解决办法就是补齐缺少的.item。因为第二行缺少1个.item,我们可以给它补上一个看不见的、高度是0的.item

<div class="box">
    ......
    <div class="item"></div>
    <div class="item placeholder"></div>
    ....
</div>


.placeholder{
    visibility: hidden;
    height: 0;
}

这时候就达到了最初的目的:

3.png

那如果每行显示4个、5个项,最后一行缺少2个、3个……怎么办?
如果你能知道你的列表最多有几个列,就可以补上几个.placeholder。如果你不确定,那么可以补多一些,保证补的.placeholder数量多于可能会出现最多的列数。因为.placeholder的高度是0,所以不会对垂直方向的布局产生影响。

这样有一个缺点:随着改变窗口大小,会发现.item之间的空隙忽大忽小。这是因为随着.box的宽度变化,行剩余的空间随之变化,行中的.item的间隙是flex动态计算的,所以会不断变化。如果你不能接受这一点,可以继续往下看。

我们设置固定的边距,并且让列表看起来两端对齐:

.box {
    ......
    /* 删掉或注释掉下面一行 */
    /* justify-content: space-between; */
    /* 设置负margin是为了让列表看上去两端对齐,两边不出现空白 */
    margin: 0 -10px 0;
    ......
}

.item可以扩展宽度并设置基本宽度:
.item {
flex: 1 200px;
/* 删掉或注释掉下面一行 /
/
width: 200px */
margin: 0 10px 20px;
}

这样,随着.box宽度的变化,.item之间的边距不再变化。但是每个.item的宽度又会跟着变化了,道理同上。不过,宽度变化视觉上要好于边距变化,个人倾向于这种方法。

下面是第二种方法的完整代码:

<div class="box">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <!-- 个数根据需要增减 -->
    <div class="item placeholder"></div>
    <div class="item placeholder"></div>
    ....
</div>


.box{
    display: flex;
    flex-wrap: wrap;
    margin: 0 -10px;
}
.item{
    flex: 1 200px;
    height: 300px;
    margin: 0 10px 20px;
}

END

标签: flex