📕 实例:九宫格

九宫格的效果应该是很多页面中都会出现的,尤其是移动端的页面中,经常可以看到几排的 icon 排列着。可能是四列的,也有可能是五列的,这些都无所谓,我们一般统称为宫格,或者九宫格。反正呢,大概就是下面这样的一个布局效果。

很显然,现在看到这个效果是最初始的一个宫格布局情况,样式大概就是这样了。

/*
  file: flex_0065.css
  九宫格效果图  1
*/
.demo {
  border: 1px solid #000;
}
/* 既然是九宫格,那就去掉最后一个 flex 元素吧 */
.item_0 {
  display: none;
}
/* 九宫格样式开始 */
.demo {
  /* 在 flex 容器超过一行的 flex 元素换行显示 */
  flex-wrap: wrap;
}
.item {
  /* 让每个 item 元素的宽度初始为 33.33%,其实也就是想让一行三列“均分”一下 */
  flex: 33.33%;
  /* 由于 item 自身有 padding,为了便于计算所以采用 border-box 的盒模型计算方式 */
  box-sizing: border-box;
}

后面的宫格例子我们也将会在这个基础上一点点添加,目前已有的样式作用目的已经通过注释的方式进行了描述。简单来说就是,希望在 flex 容器中一行显示三列宽度相同的 flex 元素,如超过 flex 容器的部分则换行显示

宫格间添加间距

现在每个宫格都是相邻在一起的,一般而言为了能够美观,每个宫格之间都是会添加一些间距来显示。在前面我们了解过,在 flex 弹性布局中,可以使用 justify-content 属性让 flex 元素在容器中产生有间隙的布局。

但是目前在这里并不合适,因为我们使用了 flex: 33.33%,无论在什么情况下,宫格中的每个 flex 元素宽度始终是 flex 容器的 33.33% 左右,且是相邻的。毕竟现在这个很自适应,很有弹性。

既然 flex 相关的属性无法满足我们的需求,那么我们可以使用别的方式来处理。但,我们不能使用 margin 的方式来处理。一旦出现 margin 相关的属性后,那么这个 flex 元素的宫格宽度就不再是 33.33%,也就无法得到一行三列的宫格了。

.item {
  /* 让每个 item 元素的宽度初始为 33.33%,其实也就是想让一行三列“均分”一下 */
  flex: 33.33%;
  /* 由于 item 自身有 padding,为了便于计算所以采用 border-box 的盒模型计算方式 */
  box-sizing: border-box;
  margin: 5px;
}

间距是有了,但是结果却不对了。

其实呢,这个时候我们完全可以利用 box-sizing 这个属性。因为 border-box 的属性值,所以当我们有 border 的时候,并不会影响 flex 元素的宽度计算结果

.item {
  /* 让每个 item 元素的宽度初始为 33.33%,其实也就是想让一行三列“均分”一下 */
  flex: 33.33%;
  /* 由于 item 自身有 padding,为了便于计算所以采用 border-box 的盒模型计算方式 */
  box-sizing: border-box;
  border: 5px solid #fff;
}

等高等宽等比的宫格

从页面布局情况来说,这样相对来说好看一点了。不过要是每个 flex 元素的宽高是相同的话,那岂不是更好。就类似现在很多 app 中的宫格排列时,都是放相同大小的 icon 图标。所以,我们也改改。

.item {
  /* 让每个 item 元素的宽度初始为 33.33%,其实也就是想让一行三列“均分”一下 */
  flex: 33.33%;
  /* 由于 item 自身有 padding,为了便于计算所以采用 border-box 的盒模型计算方式 */
  box-sizing: border-box;
  border: 5px solid #fff;
  position: relative;
  /* 这个只是为了去掉目前元素的那些数字 */
  font-size: 0;
}
.item::after {
  /* 不考虑增加额外元素而使用了 ::after,故而通过 block 块级处理 */
  display: block;
  content: '';
  position: relative;
  top: 0;
  left: 0;
  /* 宽度等于父元素的宽度 */
  width: 100%;
  /* 以父元素的宽度为标准,通过 padding 方式撑开自身的高度 */
  padding-top: 100%;
}

通过伪元素的方式撑开每个 flex 元素高度,其实宽高相同。这样就能够得到需要的宫格了。

但是这样看,是不是感觉宫格的行数太多,并且每个格子都太大了呢,一行也没放下几个。不要担心,我们只要简单修改一下 .item 中的 flex 值就可以了。

.item {
  /* 让每个 item 元素的宽度初始为 33.33%,其实也就是想让一行三列“均分”一下 */
  flex: 20%;
  ......

从 33.33% 转为 20%,现在我们可以得到的结果就是这样了。

好像哪里不对的样子,第二行的格子为什么会大一些呢。对了,因为现在是一行有 5 个格子,而我们只有 9 个元素,所以,第二行因为宽度弹性撑开了,而高度由于 padding-top 的关系也撑开了,最终导致第二行显得大一些。

要解决这个问题,我们是不是把第十个 item 展示出来就好了呢?不不不,完全没这个必要。我们只需要简简单单的加个 0 就可以了。

.item {
  /* 让每个 item 元素的宽度初始为 33.33%,其实也就是想让一行三列“均分”一下 */
  flex: 0 20%;
  ......

嗯。现在看起就舒服多了

小结

宫格的布局实现其实也是简单的,关键主要在于对 flex 这个属性的把控。这个例子中用了 padding 的方式来实现等比大小缩放的元素的,该元素可作为一个父元素插入 img,也可以直接使用 background-image 的方式插入图片。