需求描述
- 在一个容器元素下,有不确定数量的子元素,要求他们水平铺满,并且在当前行的最左边和最右边的子元素距离父元素左边缘和右边缘都是无缝贴合的。
- 每个子元素之间的间隔必须一致。
- 当浏览器窗口大小变动自适应。
尝试方案
惯性思维,一眼看过去就是 flex弹性盒子
一把梭,于是我有了以下这种方案:
index.html 文件
:
<body>
<div class="father">
<div class="child">Child1</div>
<div class="child">Child2</div>
<div class="child">Child3</div>
<div class="child">Child4</div>
<div class="child">Child5</div>
<div class="child">Child6</div>
<div class="child">Child7</div>
<div class="child">Child8</div>
<div class="child">Child9</div>
<div class="child">Child10</div>
</div>
</body>
index.scss 文件
:
.father {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: flex-start;
width: 100%;
padding: 10px 0 10px 20px;
.child {
margin-right: 14px;
margin-bottom: 14px;
// 其他卡片样式
}
}
可以看到,我会为每个子元素都设置 margin-top
以及 margin-right
来固定他们之间的间距,但是因为每一行最右边的子元素也有 margin-right
,为了补偿这个,我就将父元素的 padding-right
去掉了,这样做的坏处太多了,需要自己去计算,做补偿,而且右边有时候容纳不下一个完整的子元素,就会导致换行而留下一大片白。。
改进方案
Flex 布局是轴线布局,只能指定"项目"针对轴线的位置,可以看作是一维布局。Grid 布局则是将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局。Grid 布局远比 Flex 布局强大。
首先我们需要给容器指定为 grid
网格布局,就像 flex
一样:
.father {
display: grid;
}
接着要为其划分列数, grid-template-columns
属性可定义每一列的列宽,假如代码如下,我们将容器划分成 3
列,每列宽度为容器的 100px
:
.father {
grid-template-columns: 100px 100px 100px;
}
但是这个时候我们看到的效果会是下面这样:
子元素并没有把父元素占满,这显然不是我们想要的效果,幸亏有 repeat()
函数帮助我们简化重复值, 它接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值 。上面的代码完全可用以下代码代替:
.father {
grid-template-columns: repeat(3, 100px);
}
当然,这只是第一步,我们还需要借助 auto-fill
关键字,在我们需要容器能尽可能容纳子元素时,就需要用到它,表示自动填充,我的理解是 repeat()
接受了这个 auto-fill
的参数时,会去自动计算容纳的数量,就好像你事先算出来这个容器能容纳多少子元素,然后把这个“多少”传给该函数一样。这时候代码如下:
.father {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
}
现在图形如下,已经越来越接近我们的目标了:
但是很显然,右边有一个空隙, justify-content
属性拯救我们,它整个内容区域在容器里面的水平位置,当我设置其为 space-between
时,意味着子元素之间的间隔相等,而子元素与容器边框之间没有间隔。
不过子元素之间还是没有间隔,简单设置一下属性 gap
即可,它是 column-gap
和 row-gap
的合并简写,分别表示列与列和行与行之间的间距,现在代码如下:
.father {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
justify-content: space-between;
gap: 14px 4px;
}
由此简单的几行代码就已经完美实现了我们想要的效果:
当然,注意一下 grid
网格布局的兼容性