CSS 实现 flex布局最后一行左对齐的方案「多场景、多方案」

目录

  • 前言
  • 解决方案
    • 场景一、子项宽度固定,每一行列数固定
        • 方法一:模拟两端对齐
        • 方法二:根据元素个数最后一个元素动态margin
    • 场景二、子项的宽度不确定
        • 方法一:直接设置最后一项 margin-right:auto
        • 方法二:使用:after(伪元素)来实现最后一行的左对齐
    • 场景三、每一行列数不固定
        • 方法一:使用 Grid 布局【最佳实践】
  • 小结


前言

在CSS flex布局中,使用 justify-content 来控制列表的水平对齐方式,使用 space-around 或者 space-between 对齐时,如果最后一行的列表的个数不满,就会出现最后一行没有完全垂直对齐的问题。

如下示例:

<div class="container">
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
div>
.container {
    width: 400px;
    border: 1px solid #000;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    padding: 5px;
}
.item {
    width: 70px;
    height: 70px;
    margin-bottom: 10px;
    background-color: yellowgreen;
}

可以看到最后一行的元素个数不够,不是我们想要的效果
CSS 实现 flex布局最后一行左对齐的方案「多场景、多方案」_第1张图片

解决方案

场景一、子项宽度固定,每一行列数固定

每一行的子项宽度固定,所以列数也可固定,实现方案如下。

方法一:模拟两端对齐

原理
使用 margin 模拟 space-between 和元素之间的间隙

计算方式: 已知每一行列数是固定的,比如每一行5(n)列
剩余可使用宽度 = .container容器宽度 - (.item宽度 * 5) width = 400 - (70 * 5) = 50
设置margin = 剩余可使用宽度 / (5 - 1) marginRight = 50 / (5 - 1) = 12.5
公示合并 marginRight = (.container容器宽度 - (.item宽度 * n)) / (n-1)

.container {
  	width: 400px;
    border: 1px solid #000;
    display: flex;
    flex-wrap: wrap;
    /* justify-content: space-between; */
    padding: 5px;
}
.item {
    width: 70px;
    height: 70px;
    margin-bottom: 10px;
    background-color: yellowgreen;
}
.item:not(:nth-child(5n)) {
    margin-right: 12.5px;
}

效果如下:
CSS 实现 flex布局最后一行左对齐的方案「多场景、多方案」_第2张图片

方法二:根据元素个数最后一个元素动态margin

原理
动态设置margin指的是设置最后一个元素的margin值。
比如我们每一行5个元素,但是最后一行只有4个元素,此时如果我们将最后一行的最后一个元素的右边距设置为元素宽度+间隙宽度,那么是可以实现左对齐效果的。

计算方式: 针对最后一行,分别有一个元素,有两个元素,有三个元素,有四个元素等情况
.item:last-child:nth-child(5n - 1) => 当n为1时,5n-1=4,代表是第四个元素,marginRight 就是第五个元素的 width+1个空隙的宽度
.item:last-child:nth-child(5n - 2) => 当n为1时,5n-2=3,代表是第三个元素,marginRight 就是第四个元素的 width+第五个元素的width+2个空隙的宽度
以此类推…
.item:last-child:nth-child(5n - m),需要之前【方法一】中计算的 _marginRight = (.container容器宽度 - (.itemWidth * n)) / (n-1)
推算公示 marginRight = (.itemWidth * m + _marginRight * m)

.container {
  	width: 400px;
    border: 1px solid #000;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    padding: 5px;
}
.item {
    width: 70px;
    height: 70px;
    margin-bottom: 10px;
    background-color: yellowgreen;
}
/* 当n为1时,5n-1=4,代表是第四个元素,margin-right就是第五个元素的width+1个空隙的宽度 */
.item:last-child:nth-child(5n - 1) {
    margin-right: 82.5px;
}
/* 当n为1时,5n-2=3,代表是第三个元素,margin-right就是第四个元素的width+第五个元素的width+2个空隙的宽度 */
.item:last-child:nth-child(5n - 2) {
    margin-right: 165px;
}
/* 当n为1时,5n-3=2,代表是第二个元素,margin-right就是第三个元素的width+第四个元素的width+第五个元素的width+3个空隙的宽度 */
.item:last-child:nth-child(5n - 3) {
    margin-right: 247.5px;
}

效果如下:

CSS 实现 flex布局最后一行左对齐的方案「多场景、多方案」_第3张图片

场景二、子项的宽度不确定

当每一个子元素宽度不固定时,此时的元素间隙的大小也不固定,所以相对来说处理更简单。

方法一:直接设置最后一项 margin-right:auto

原理
让最后一个元素的右边距自动适应,从而实现左对齐的效果

style

.container {
    width: 400px;
    border: 1px solid #000;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    padding: 5px;
}

.item {
    width: 70px;
    height: 70px;
    margin: 10px;
    background-color: yellowgreen;
}
.item:last-child {
    margin-right: auto;
}

html 改造

<div class="container">
   	<div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
    <div class="item">div>
div>
<script>
	// 动态随机设置 .item 宽度
    let itemDiv = document.querySelectorAll(".container .item");
    for (var i = itemDiv.length - 1; i >= 0; i--) {
        itemDiv[i].style.width = rand(70, 40) + "px";
    }
    function rand(max, min) {
        return Math.floor( Math.random() * (max - min + 1) + min);
    }
script>

效果如下(容器尺寸不变的情况下):
CSS 实现 flex布局最后一行左对齐的方案「多场景、多方案」_第4张图片
效果2如下(容器尺寸变的情况下):
CSS 实现 flex布局最后一行左对齐的方案「多场景、多方案」_第5张图片

方法二:使用:after(伪元素)来实现最后一行的左对齐

原理
使用css中的 :after(伪元素) 给 父容器 设置 flex:autoflex:1 来实现最后一行的左对齐,使用伪元素进行占位

style 改造

.container {
    width: 400px;
    border: 1px solid #000;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    padding: 5px;
}

.item {
    width: 70px;
    height: 70px;
    margin: 10px;
    background-color: yellowgreen;
}
.container::after {
   	content: '';
    flex: auto;    
    /* 或者flex: 1 */
}

html 改造同【方法一】中的html

效果与【方法一】中实现效果相同

场景三、每一行列数不固定

每一行的列数不固定,那么上面的那些方法均不适用,请看如下方案

当我们布局的列表个数不固定,这个时候我们不妨可以换一种思维,试试使用 Grid 布局。

方法一:使用 Grid 布局【最佳实践】

原理
Grid 布局天然有 gap 间隙,且格子对齐排布,因此,实现最后一行左对齐可以认为是最佳效果。
代码解释:
display: grid 指定一个容器采用网格布局
grid-template-columns 属性定义每一列的列宽
grid-gap 属性定义网格布局中行与列之间间隙的尺寸,它是 grid-row-gap & grid-column-gap 属性的简写

其实起来非常简单,且代码简明,请见如下代码

.container {
    width: 400px;
    border: 1px solid #000;
    padding: 5px;
    display: grid;
    justify-content: space-between;
    grid-template-columns: repeat(auto-fill, 80px);
    grid-gap: 10px;
}

.item {
    width: 70px;
    height: 70px;
    margin: 10px;
    background-color: yellowgreen;
}

效果如下(容器尺寸不变的情况下):

CSS 实现 flex布局最后一行左对齐的方案「多场景、多方案」_第6张图片

效果2如下(容器尺寸变的情况下):

CSS 实现 flex布局最后一行左对齐的方案「多场景、多方案」_第7张图片

小结

综上可见,最后一行左对齐的布局需求更适合使用 CSS grid 布局来实现,但是,repeat() 函数兼容性有些要求,IE浏览器并不支持。如果项目需要兼容IE,则此方法有待商榷。

使用上面的提供的几种方案:动态计算margin、模拟两端对齐、根据列表的个数动态控制最后一个列表元素的margin值均可正确实现左对齐效果。

所有方案各有利弊,大家还得根据自己的实际场景,选择适合当前项目的合适的方法。

如果你有其他更好的实现解决方案,欢迎评论区留言讨论,大家一起学习进步~

希望上面的内容对你的工作学习有所帮助!欢迎各位一键三连哦~

Happy coding!

你可能感兴趣的:(前端,前端面试,CSS,系列,css,前端,flex,面试,学习方法)