如何构建一个响应式网格系统(一)

475 阅读5分钟

前言

截屏2022-05-27 17.49.18.png

相信大家都能够轻松的编写上面布局的代码

如果是下面的布局呢?你会怎么样编写?

截屏2022-05-27 17.49.29.png

它们的2栏和3 栏 布局是相似的。只是列的宽度不一样。

我们可能就会 复制同样的代码,然后修改宽度。来扩展 成为 不同的布局。

这样的方式很容易出错,扩展性、复用性也较差。

有没有一种设计方法,可以让我们灵活的快速的生成我们所需要的布局。

当然有,

css网格系统(栅格系统)

运用固定的格子,遵循一定的规则,进行页面的布局设计,使布局规范简洁有规则

它存在于很多的框架 和组件当中。相信大家都有用过。也感受到了网格系统的强大。

它把页面等分为 8列 、12列 、或者24列(至于为什么是8列、12列 、或者24列,大家可以参阅 网格设计规范)

截屏2022-05-27 18.38.55.png

我们可以在此基础上 通过 组合 不同的列 来 衍生出 很多不同的排版方案。非常灵活,具有很高的延展性。

截屏2022-05-27 18.34.45.png

实现1个网格系统,我们可以基于 float 、flex 或者 grid 当中的其中一种排版技术就可以。

我们主要是讲解 基于 flex的 网格系统

网格的基础概念

网格宽度

这里我们不采用固定的宽度,而是100%。如果你需要固定的宽度,可以外层加一个容器。

截屏2022-05-27 20.16.46.png

列数

将整个网格宽度 等分为 多少列 (100% / 24)  。这里我们基于24列

截屏2022-05-27 20.22.22.png

列宽和间隔

列宽

  • 网格列宽: 整个网格等分之后每一列的宽度
  • 内容列宽: 一块内容通常会占用1个或者多个列的宽度,我们把这个区域理解为内容区域,用于承载一个区域的内容。

间隔(gutter)

  • 列与列之间的距离

占据1个网格列宽的内容列宽

截屏2022-05-28 09.16.27.png

占据2个网格列宽的内容列宽

截屏2022-05-28 09.17.27.png

计算列宽

eg: 网格宽度 960px, 等分分为12列

网格列宽: 960 / 12 = 80

内容列宽 :

  • 如果间隔为0: 内容列宽 = 网格列宽
  • 如果间隔不为0 (gutter = 20)
    • 由于使用 flex 的 属性gap 设置间距,最后一个列右侧是没有间距的。所以会有20的剩余空间,flex 会把剩余的空间 平均分配到网格的粉色区域上。粉色区域主要是承载内容的。所以也叫内容区域。
    • 内容列宽为: (网格列宽 - 间隔) + 间隔/12 = 61.66

截屏2022-05-27 22.09.50.png

从上面可以看出 内容列宽 是基于网格列宽计算的

通常内容列宽是占有1个或者多个网格列宽

如果内容列宽占1个网格列宽(1个网格列宽为80, 粉色区域 + 间隔 = 81.66)

是下面这样占据的, 间隔处还有剩余1.66的空间。

截屏2022-05-27 22.23.36.png

而内容列宽是粉色的区域 不应该包含右侧的占据已有的间隔(此时并没有完全占有间隔,间隔还有1.66的空间)

截屏2022-05-27 22.25.43.png

如何计算内容的列宽呢?

内容列宽 = 网格列宽 - 占据的间隔宽度

占据的间隔宽度 = 间隔宽度 - 间隔宽度 / 12

所以

  • 占据1个网格列宽的内容宽度 =  网格列宽 - (间隔 - 间隔/12)  
  • 占据2个网格列宽的内容宽度 =  网格列宽 * 2 - (间隔 - 间隔/12 * 2) ...
  • 占据12个网格列宽的内容宽度 =  网格列宽 * 12 - (间隔 - 间隔/12 * 12) = 网格宽度 * 12

那么有么有更好的容易理解的计算方法呢?

我们只需要把网格列宽 从原来的80 变为 81.66

那么1个网格列宽正好就是 内容列宽+ 间隔

截屏2022-05-27 23.08.18.png

  • 占据1个网格列的内容列宽 = 网格列宽 - 间隔

截屏2022-05-28 08.44.30.png

  • 占据2个网格列的内容列宽 = 网格列宽 * 2 - 间隔

截屏2022-05-28 08.44.55.png

  • 占据3个网格列的内容列宽 = 网格列宽 * 3 - 间隔

......

这样计算是不是更容易呢?

问题来了

那怎么 把 网格列宽 从80 变成81.66呢?

这多出1.66 正好是 间隔20 等分12 的值。 

那是不是把 网格宽度 + 1个间隔的距离  再等分12 就变成81.66呢?

所以网格列宽 计算方式从原来的 960 / 12  变为 (960 + 20 ) / 12

你可能会疑惑 网格宽度在增加20 不就变成 980呢。会不会多出 20的空间?

答案是 不会的。接下来,我们来推导一下。

eg:

  • 内容列宽 占 1个网格列宽,那么 就是  ( 960 + 20)/ 12 - 20

截屏2022-05-27 23.11.59.png

  • 内容的宽度 占 2列,那么 就是  ((960 + 20)/ 12) * 2 - 20

截屏2022-05-28 00.56.14.png

以此类推

.......

如果内容列宽所占的网格列包含最后一个网格列呢?

eg:

内容宽度 占据12个网格列宽

内容宽度 =  (960 + 20) / 12 * 12

截屏2022-05-27 22.41.53.png

你会发现内容列宽变成了980了,也就是超出了网格宽度

而内容列宽 是不占据最右侧那多出来的空间的

我们把内容列宽减去20 是不是正好和网格宽度增加的20 相互抵消了呢?

也满足了我们12列所占的内容宽度为960了。

这样不管占据多少网格列的内容列宽计算公式是不是就一致了呢?

计算公式

  • 网格列宽 =  (网格宽度 + 间隔) / 列数

  • 占据N个网格列宽的内容列宽 =  网格宽度 * N - 间隔

理解了这些概念之后, 下一节我们将用具体的代码来实现。