在日常开发中,我们经常会遇到要求在一个容器内元素两端对齐的需求,这里总结了几种实现的方法,大家可以根据实际情况选择合适的方案。
第一种情况,当列数固定,子项宽度固定
这里按照每行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:文章中有些是个人观点,如果不对,欢迎交流、指正!
参考资料
- 浮动(developer.mozilla.org/zh-CN/docs/…)
- Flex 布局(www.ruanyifeng.com/blog/2015/0…)
- Grid 网格布局(www.ruanyifeng.com/blog/2019/0…)
- caniuse(caniuse.com/?search=rep…)