两端对齐,最后一行左对齐的几种做法

1,178 阅读6分钟

在日常开发中,我们经常会遇到要求在一个容器内元素两端对齐的需求,这里总结了几种实现的方法,大家可以根据实际情况选择合适的方案。

第一种情况,当列数固定,子项宽度固定

这里按照每行4列为例

使用Float

如果你把几个设置float的元素放到一起,如果有空间的话,它们将彼此相邻。如果想实现列表两端对齐的话,那必须给元素设置相应的宽度和边距。

.container {
    overflow: hidden;
}
.content {
    margin-left: -2%;
}
.container .item {
    color: #fff;
    line-height: 1.5em;
    text-align: center;
    width: 23%;
    height: 100px;
    background-color: #2193b0;
    float: left;
    margin-top: 2%;
    margin-left: 2%;
}
<div class="container">
    <div class="content"> 
        <div class="item">item 1</div>
        <div class="item">item 2</div>
        <div class="item">item 3</div>
        <div class="item">item 4</div>
        <div class="item">item 5</div>
        <div class="item">item 6</div>
        <div class="item">item 7</div>
        <div class="item">item 8</div>
        <div class="item">item 9</div>
        <div class="item">item 10</div>
    </div>
</div>

元素浮动之后,会脱离正常的文档布局流,在正常布局中位于该浮动元素之下的内容,此时会围绕着浮动元素,填满其右侧的空间,为了避免这种情况,可以使用 clear 属性或者使用 overflow: hidden清除浮动。

clear 可以取三个值:

  • left:停止任何活动的左浮动
  • right:停止任何活动的右浮动
  • both:停止任何活动的左右浮动

使用inline-block

子级元素设置inline-block,将块级元素转化为内联块元素,但是使用 inline-block 会产生空白符,那么问题来了,怎么去除这些间隙呢?要去除空白符产生的间隙,首先要理解空白符归根结底是个字符,既然是字符,那就可以通过设置font-size控制产生的间隙的大小,那么这时候我们就可以在父级元素添加font-size: 0,去除子级元素产生的间隙。

.container {
    overflow: hidden;
}
.container .content {
    font-size: 0;
    /* letter-spacing: -1em; */
    margin-left: -2%;
}
.container .item {
    font-size: 16px;
    color: #fff;
    /* letter-spacing: 0; */
    line-height: 1.5em;
    text-align: center;
    width: 23%;
    height: 100px;
    background-color: #2193b0;
    display: inline-block;
    margin-left: 2%;
    margin-bottom: 2%;
}
<div class="container">
    <div class="content">
        <div class="item">item 1</div>
        <div class="item">item 2</div>
        <div class="item">item 3</div>
        <div class="item">item 4</div>
        <div class="item">item 5</div>
        <div class="item">item 6</div>
        <div class="item">item 7</div>
        <div class="item">item 8</div>
        <div class="item">item 9</div>
        <div class="item">item 10</div>
    </div>
</div>

除了给父级元素设置 font-size: 0 之外,还可以设置letter-spacing: -1em,这里使用了letter-spacing相对单位em表示距离,所以不需要根据字体大小改变代码来去除元素间距,但是子级元素需要设置letter-spacing: 0,使子级元素恢复默认间距。

使用Flex

flex的justify-content属性可以实现列表的水平对齐方式,例如space-between可以两端对齐,但是如果最后一行的个数不满的话,会导致没办法完全垂直对齐,如下图所示,这样的显示效果,不是很符合我们平时的显示需求,那么要怎么解决呢?接下来我们来感受一下css的神奇吧。

1.利用 :last-child 的 margin 占位

.container {
    overflow: hidden;
}
.container .content {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    margin-left: -2%;
}
.container .item {
    color: #fff;
    line-height: 1.5em;
    text-align: center;
    width: 23%;
    height: 100px;
    background-color: #2193b0;
    margin-top: 2%;;
    margin-left: 2%;
}
.container .item:last-child {
    margin-right: auto;
}

2.利用父级的 :after 占位

利用父级的after使用flex:auto或者flex:1把剩余的位置撑开

.container {
    overflow: hidden;
}
.container .content {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    margin-left: -2%;
}
.container .item {
    color: #fff;
    line-height: 1.5em;
    text-align: center;
    width: 23%;
    height: 100px;
    background-color: #2193b0;
    margin-top: 2%;;
    margin-left: 2%;
}
.container .content:after{
    content: '';
    flex: auto;
    /* flex: 1; */
}
<div class="container">
    <div class="content"> 
        <div class="item">item 1</div>
        <div class="item">item 2</div>
        <div class="item">item 3</div>
        <div class="item">item 4</div>
        <div class="item">item 5</div>
        <div class="item">item 6</div>
        <div class="item">item 7</div>
        <div class="item">item 8</div>
        <div class="item">item 9</div>
        <div class="item">item 10</div>
    </div>
</div>

3.利用:last-child和:nth-child()占位

通过计算倒数第二个和第三个元素的margin-right值来占位

.container {
    overflow: hidden;
}
.container .content {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    margin-left: -2%;
}
.container .item {
    color: #fff;
    line-height: 1.5em;
    text-align: center;
    width: 23%;
    height: 100px;
    background-color: #2193b0;
    margin-top: 2%;;
    margin-left: 2%;
}
.container .item:last-child:nth-child(4n-2) {/* 如果是2个元素 */
    margin-right: calc(100% - 46% - 4%);
}
.container .item:last-child:nth-child(4n-1) {/* 如果是3个元素 */
    margin-right: calc(100% - 69% - 6%);
}
<div class="container">
    <div class="content"> 
        <div class="item">item 1</div>
        <div class="item">item 2</div>
        <div class="item">item 3</div>
        <div class="item">item 4</div>
        <div class="item">item 5</div>
        <div class="item">item 6</div>
        <div class="item">item 7</div>
        <div class="item">item 8</div>
        <div class="item">item 9</div>
        <div class="item">item 10</div>
    </div>
</div>

4.利用 :not() 来计算其他元素的 margin值占位,模仿space-between的间隙

.container {
    overflow: hidden;
}
.container .content {
    display: flex;
    flex-wrap: wrap;
}
.container .item {
    color: #fff;
    line-height: 1.5em;
    text-align: center;
    width: 23%;
    height: 100px;
    background-color: #2193b0;
    margin-top: 2%;;

}
.container .item:not(:nth-child(4n)) {
    margin-right: calc(8% / 3);
}
<div class="container">
    <div class="content"> 
        <div class="item">item 1</div>
        <div class="item">item 2</div>
        <div class="item">item 3</div>
        <div class="item">item 4</div>
        <div class="item">item 5</div>
        <div class="item">item 6</div>
        <div class="item">item 7</div>
        <div class="item">item 8</div>
        <div class="item">item 9</div>
        <div class="item">item 10</div>
    </div>
</div>

使用Grid

容器指定了网格布局以后,通过grid-template-columns分成4列,使用repeat()函数,简化重复的值,使用fr表示比例关系。

.container {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    /* 等同 grid-template-columns: 1fr 1fr 1fr 1fr; */
    gap: 10px;
}
.container .item {
    color: #fff;
    line-height: 1.5em;
    text-align: center;
    height: 100px;
    background-color: #2193b0;
}
<div class="container">
    <div class="item"><span>1</span></div>
    <div class="item"><span>2</span></div>
    <div class="item"><span>3</span></div>
    <div class="item"><span>4</span></div>
    <div class="item"><span>5</span></div>
    <div class="item"><span>6</span></div>
    <div class="item"><span>7</span></div>
    <div class="item"><span>8</span></div>
    <div class="item"><span>9</span></div>
    <div class="item"><span>10</span></div>
</div>

第二种列数不固定,子项宽度固定

使用Flex

通过设置内联元素的个数等同最大列数(比如一行最多显示10列,那么就需要设置10个span),通过span的宽度来撑开剩余的容器宽度,因为span没有设置高度,所以只会影响容器水平方向的布局而不会影响垂直方向的布局。

.container {
    overflow: hidden;
}
.container .content {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    margin-left: -10px;
}
.container .item {
    color: #fff;
    line-height: 1.5em;
    text-align: center;
    width: 100px;
    height: 100px;
    background-color: #2193b0;
    margin-left: 10px;
    margin-top: 10px;
}
.container .content > span {
    width: 100px;
    margin-left: 10px;
}
<div class="container">
    <div class="content"> 
        <div class="item"><span>item 1</span></div>
        <div class="item"><span>item 2</span></div>
        <div class="item"><span>item 3</span></div>
        <div class="item"><span>item 4</span></div>
        <div class="item"><span>item 5</span></div>
        <div class="item"><span>item 6</span></div>
        <div class="item"><span>item 7</span></div>
        <div class="item"><span>item 8</span></div>
        <div class="item"><span>item 9</span></div>
        <div class="item"><span>item 10</span></div>
        <span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
    </div>
</div>

使用Grid

有时候,当我们没有办法去调整html结构,而且列表个数又不固定,这个时候该如何实现我们最后一行左对齐效果呢?我们不妨试试使用Grid布局。
Grid布局可以通过gap设置间隙,而且格子自动对齐排布,所以可以很轻松实现最好一行左对齐,通过auto-fill可以自动填充列数,使得每一行容纳尽可能多的单元格。

.container {
    display: grid;
    grid-template-columns: repeat(auto-fill, 100px);
    gap: 10px;
    justify-content: space-between;
}
.container .item {
    color: #fff;
    line-height: 1.5em;
    text-align: center;
    height: 100px;
    background-color: #2193b0;
}
<div class="container">
    <div class="item"><span>item 1</span></div>
    <div class="item"><span>item 2</span></div>
    <div class="item"><span>item 3</span></div>
    <div class="item"><span>item 4</span></div>
    <div class="item"><span>item 5</span></div>
    <div class="item"><span>item 6</span></div>
    <div class="item"><span>item 7</span></div>
    <div class="item"><span>item 8</span></div>
    <div class="item"><span>item 9</span></div>
    <div class="item"><span>item 10</span></div>
</div>

第三种列数不固定,子项宽度不固定

使用Flex

.container {
    overflow: hidden;
}
.container .content {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    margin-left: -2%;
}
.container .item {
    color: #fff;
    line-height: 1.5em;
    text-align: center;
    height: 100px;
    background-color: #2193b0;
    margin-top: 2%;;
    margin-left: 2%;
}
.container .content:after{
    content: '';
    flex: auto;
    /* flex: 1; */
}
<div class="container">
    <div class="content"> 
        <div class="item" style="width: 100px">item 1</div>
        <div class="item" style="width: 80px">item 2</div>
        <div class="item" style="width: 140px;">item 3</div>
        <div class="item" style="width: 70px;">item 4</div>
        <div class="item" style="width: 100px;">item 5</div>
        <div class="item" style="width: 150px;">item 6</div>
        <div class="item" style="width: 70px;">item 7</div>
        <div class="item" style="width: 100px;">item 8</div>
        <div class="item" style="width: 80px;">item 9</div>
        <div class="item" style="width: 120px;">item 10</div>
    </div>
</div>

最后总结

这几种方法各有各的优缺点,大家可以根据实际情形选择合适的方法。 但是在grid布局中,IE浏览器不支持repeat()函数,所以如果需要考虑IE的兼容性的话,grid的repeat()这个方法要慎重考虑。 PS:文章中有些是个人观点,如果不对,欢迎交流、指正!

参考资料