目录
- 前言
- 解决方案
- 场景一、子项宽度固定,每一行列数固定
- 方法一:模拟两端对齐
- 方法二:根据元素个数最后一个元素动态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;
}
👇 可以看到最后一行的元素个数不够,不是我们想要的效果
解决方案
场景一、子项宽度固定,每一行列数固定
每一行的子项宽度固定,所以列数也可固定,实现方案如下。
方法一:模拟两端对齐
👉 原理
使用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;
}
👇 效果如下:
方法二:根据元素个数最后一个元素动态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;
}
👇 效果如下:
场景二、子项的宽度不确定
当每一个子元素宽度不固定时,此时的元素间隙的大小也不固定,所以相对来说处理更简单。
方法一:直接设置最后一项 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>
👇 效果如下(容器尺寸不变的情况下):
👇 效果2如下(容器尺寸变的情况下):
方法二:使用:after(伪元素)来实现最后一行的左对齐
👉 原理
使用css中的:after
(伪元素) 给 父容器 设置flex:auto
或flex: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;
}
👇 效果如下(容器尺寸不变的情况下):
👇 效果2如下(容器尺寸变的情况下):
小结
综上可见,最后一行左对齐的布局需求更适合使用 CSS grid 布局来实现,但是,repeat()
函数兼容性有些要求,IE浏览器并不支持。如果项目需要兼容IE,则此方法有待商榷。
使用上面的提供的几种方案:动态计算margin、模拟两端对齐、根据列表的个数动态控制最后一个列表元素的margin值均可正确实现左对齐效果。
所有方案各有利弊,大家还得根据自己的实际场景,选择适合当前项目的合适的方法。
如果你有其他更好的实现解决方案,欢迎评论区留言讨论,大家一起学习进步~
希望上面的内容对你的工作学习有所帮助!欢迎各位一键三连哦~
Happy coding!