网格布局(Grid Layout)也叫栅格布局,与表格布局类似,也依赖行和列。但与之不同的是,网格布局能直接控制HTML文档中元素的顺序、位置和大小等,而不用再借助辅助元素。
## 一、术语
  下图展示了CSS规范中定义的网格。
:-: ![](https://img.kancloud.cn/bb/6a/bb6a137cc4006d6d512da2bbd000178c_782x691.png =400x)
  (1)网格容器(grid container)由display属性的两个特殊值(grid和inline-grid)所创建,由于它不是块级容器,因此其布局不受浮动和外边距塌陷的影响。
  (2)网格项(grid item)也叫网格元素,是网格容器的子元素,注意,它的后代元素不是网格项,但它自身也能变为网格容器。
  (3)网格线(grid line)为网格容器划分不同的区域,注意,网格线的数量没有限制。
  (4)网格单元(grid cell)是由四条网格线限定的区域,其内部不会有其它的网格线。
  (5)网格区域(grid area)由一个或多个相邻的网格单元组成的矩形区域,最大的网格区域会包含所有的网格单元。
  (6)网格轨道(grid track)是由两条网格线夹住的区域,从容器的一边延伸到另一边,水平方向的叫网格行(grid row),垂直方向的叫网格列(grid column),它们的尺寸由网格线的位置决定。
## 二、行和列
  grid-template-rows和grid-template-columns两个属性可以定义网格线的名称和网格轨道的尺寸,前者可声明行的数量,后者可声明列的数量。
  在下面的示例中,将网格容器分成两行三列,其中第一列的宽度是50px(即第二条网格线在距离容器左边界50px的位置),第二列的宽度是容器宽度的一半(即第三条网格线距离上一条网格线的偏移是容器宽度的一半),第三列的宽度是30px。
~~~html
<style>
div {
display: grid;
width: 200px;
height: 100px;
grid-template-rows: 50px 50px;
grid-template-columns: 50px 50% 30px;
}
</style>
<div>
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
<section>5</section>
<section>6</section>
</div>
~~~
  下图的左侧是上述代码的效果,右侧中的虚线是生成的网格线,后文会反复使用这种格式的标注图。注意,网格线可以不与容器的边界接触,两个属性中的百分数参照的是网格容器的宽度或高度。
:-: ![](https://img.kancloud.cn/80/a1/80a18657b36d31e668910acfa7b21c46_855x213.png =400x)
  如果要占满网格容器的横向空间,那么可以使用minmax()函数,如下所示。minmax(30px, 100%)表示该列所占的空间在30px和容器宽度之间,即不能小于30px并且不能大于容器宽度,效果如下图所示。
~~~css
div {
grid-template-columns: 50px 50% minmax(30px, 100%);
}
~~~
:-: ![](https://img.kancloud.cn/57/0e/570e4c8785a019f53c5c7b92406758ff_855x213.png =400x)
  如果要为网格线命名,那么可以将名称放在值的恰当位置(例如名称在值之前,样式如下),并用方括号包裹。
~~~css
div {
grid-template-columns: [col-a] 50px [col-b] 50% [col-c] minmax(30px, 100%) [col-d];
}
~~~
**1)fr**
  在网格布局中,包含一个全新的fr单位,能将空间分成一定份数,弹性的分配给行或列,这个单位的作用类似于弹性盒中的flex-grow属性。在下面的示例中,将容器均分为3列,效果如下图所示。
~~~css
div {
grid-template-columns: 1fr 1fr 1fr;
}
~~~
:-: ![](https://img.kancloud.cn/cb/83/cb83decdf66e8cfdd46b128259d14f19_855x213.png =400x)
  注意,fr可与其它长度单位混合使用,其作用的是可用空间,即剩余空间。在下面的示例中,将第一列宽度固定,剩余的空间由两列均分,效果如下图所示。
~~~css
div {
grid-template-columns: 30px 1fr 1fr;
}
~~~
:-: ![](https://img.kancloud.cn/45/cc/45cc9fe78d71bed64b4f02c9dd18c4f9_855x213.png =400x)
**2)min-content和max-content**
  当网格轨道的尺寸与其内容有关时,可使用这两个关键字。min-content会占据内容所需的最小空间,例如将min-content应用于网格容器的第二列,样式如下,效果如下图所示,网格项中有大量的断行。
~~~html
<style>
div {
grid-template-columns: 30px min-content 1fr;
}
</style>
<div>
<section>1</section>
<section>2 2 2</section>
<section>3</section>
<section>4</section>
<section>5</section>
<section>6</section>
</div>
~~~
:-: ![](https://img.kancloud.cn/67/5a/675af563bed3655dea272511c3b5218f_855x213.png =400x)
  max-content的作用正好与min-content相反,它会占据内容所需的最大空间。将max-content也应用到上面的第二列,样式如下,效果如下图所示,网格项为了防止文本换行,会不断地扩大其宽度。
~~~css
div {
grid-template-columns: 30px max-content 1fr;
}
~~~
:-: ![](https://img.kancloud.cn/21/2b/212bb3763c47c5b4b059a2f2cd342bde_855x213.png =400x)
**3)fit-content()**
  该函数的参数是一个长度值或百分数,能将占用空间指定成特定的值,它相当于下面等号右边的公式。
~~~
fit-content(argument) = min(max-content, max(min-content, argument))
~~~
  先将接收的参数与min-content比较,得出较大值,再将该值与max-content比较,得到较小值。理解起来比较拗口,如果换成minmax()函数,含义就比较清晰了,与fit-content(argument)等价的公式如下。
~~~
minmax(min-content, max-content)
~~~
**4)repeat()**
  该函数能为网格轨道声明重复的行或列,它的第一个参数是重复次数,第二个参数是轨道尺寸,例如将网格容器均分成三列,样式如下。
~~~css
div {
grid-template-columns: repeat(3, 1fr);
/* 等价于 */
grid-template-columns: repeat(1fr, 1fr, 1fr);
}
~~~
  注意,轨道尺寸不局限于一个,可以指定多个,样式如下,效果如下图所示。
~~~css
div {
grid-template-columns: repeat(2, 20px 1fr);
}
~~~
:-: ![](https://img.kancloud.cn/d9/7f/d97f4f6ae4eb6334396847d405dee83e_855x213.png =400x)
## 三、网格项
  通过起始和终止处的网格线的名称或编号可指定网格项的位置,其中列的编号从左到右依次递增,行的编号从上到下依次递增,如下图所示。
:-: ![](https://img.kancloud.cn/34/c2/34c2f44bba0689196e30dd8aadb61372_287x219.png =300x)
  在下面的示例中,将网格容器均分成三行四列,并且把第一个section元素指定到第二行第二列的位置,效果如下图所示。
~~~html
<style>
div {
grid-template-rows: repeat(3, 1fr);
grid-template-columns: repeat(4, 1fr);
}
.one {
grid-row-start: 2;
grid-row-end: 3;
grid-column-start: 2;
grid-column-end: 3;
}
</style>
<div>
<section class="one">1</section>
<section>2</section>
<section>3</section>
<section>4</section>
<section>5</section>
<section>6</section>
<section>7</section>
<section>8</section>
<section>9</section>
<section>10</section>
</div>
~~~
:-: ![](https://img.kancloud.cn/01/d8/01d87a7c0dec3a5506e3975f7c009c10_855x213.png =400x)
  将下面的样式添加给第一个section元素,可以得到跨列的效果,如下图所示。
~~~css
.two {
grid-row-start: 2;
grid-row-end: 3;
grid-column-start: 2;
grid-column-end: 4;
}
~~~
:-: ![](https://img.kancloud.cn/ac/52/ac5207b276fa711dc834dc3f74aed1e2_855x213.png =400x)
  网格线的编号支持负数,也就是以相反的方式计数,从后往前或从下往上,例如将第一个section元素放置在容器的右下角,样式如下,效果如下图所示。
~~~css
.three {
grid-row-start: -2;
grid-row-end: -1;
grid-column-start: -2;
grid-column-end: -1;
}
~~~
:-: ![](https://img.kancloud.cn/5e/30/5e30676c8524d1db39741ed65c45864d_855x213.png =400x)
**1)span**
  还有另一种方式可用来指定网格项的位置,即用span和正整数组合,表示要跨的网格轨道数目。在下面的样式中,“span 2”用于跨过两列。
~~~css
.four {
grid-row-start: 2;
grid-row-end: 3;
grid-column-start: 2;
grid-column-end: span 2;
}
~~~
  当把span应用于grid-row-start或grid-column-start属性时,将会沿着网格开始的方向计数,样式如下,效果如下图所示。
~~~css
.five {
grid-row-start: 2;
grid-row-end: 3;
grid-column-start: span 2;
grid-column-end: 3;
}
~~~
:-: ![](https://img.kancloud.cn/78/04/780491cb0e2fedb7442ce2b8b9f7eb7d_855x213.png =400x)
  注意,span后面可以省略数字,默认是1,但不能跟零或负数。
**2)简写属性**
  grid-row是grid-row-start和grid-row-end的简写属性,grid-column是grid-column-start和grid-column-end的简写属性。
  grid-row和grid-column可分别将行和列的起止网格线声明在一行,并用斜杠(/)分隔,如下所示。
~~~css
.six {
grid-row: 2 / 3;
grid-column: 2 / span 2;
}
~~~
  注意,由于默认跨度是1,因此可以省略grid-row和grid-column斜杠后的数字,如下所示。
~~~css
.seven {
grid-row: 2;
grid-column: 2;
}
~~~
  grid-area是grid-row-start、grid-row-end、grid-column-start和grid-column-end的简写属性,也可用斜杠(/)将值分隔,如下所示。
~~~css
.eight {
grid-area: 2 / 2 / 3 / span 2;
}
~~~
  注意,网格线值的顺序是:起始行、起始列、终止行、终止列,围绕网格项逆时针排列。
**3)重叠**
  当两个网格项发生重叠时,可通过z-index属性来决定谁在上,谁在下。例如为两个section元素分别添加下面的样式,效果如下图所示,第二个section元素覆盖了第一个section元素。
~~~html
<style>
.overlap1 {
grid-row: 1;
grid-column: 1 / span 2;
}
.overlap2 {
grid-row: 1;
grid-column: 2 / span 2;
}
</style>
<div>
<section class="overlap1">1</section>
<section class="overlap2">2</section>
<section>3</section>
<section>4</section>
<section>5</section>
<section>6</section>
<section>7</section>
<section>8</section>
<section>9</section>
<section>10</section>
</div>
~~~
:-: ![](https://img.kancloud.cn/ab/fa/abfa6ff59980f4cf46f9f380581f346a_412x213.png =300x)
  当为第一个section元素添加z-index属性后(样式如下),就会覆盖第二个section元素,效果如下图所示。
~~~css
.overlap1 {
z-index: 1;
}
~~~
:-: ![](https://img.kancloud.cn/09/15/09153c411166b7ce2cfa0ac2fc90c843_411x213.png =300x)
**4)自动增加网格线**
  当网格项超出容器边界时,可通过grid-auto-rows和grid-auto-columns分别控制行和列的尺寸。
  在下面的示例中,将网格容器分成两行三列,它的第七个超出边界的网格项的高度默认是内容的高度,即“height:auto”,效果如下图所示。
~~~html
<style>
div {
grid-template-rows: 50px 50px;
grid-template-columns: repeat(3, 1fr);
}
</style>
<div>
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
<section>5</section>
<section>6</section>
<section>7</section>
</div>
~~~
:-: ![](https://img.kancloud.cn/1c/b1/1cb142d4042893dc14af75bdacb99187_413x258.png =300x)
  当为网格容器添加grid-auto-rows属性后,就能改变网格项的高度,如下所示,效果如下图所示。
~~~css
div {
grid-auto-rows: 50px;
}
~~~
:-: ![](https://img.kancloud.cn/49/10/491056c21185691a2c2a6d8c211da8f7_413x310.png =300x)
  grid-auto-columns的用法与之类似,但修改的是超出边界的网格项的宽度。在下图中,左侧是默认超出时的宽度,即内容的宽度(width:auto);右侧是为容器添加下面样式后的宽度。
~~~css
div {
grid-auto-flow: column;
grid-auto-columns: 50px;
}
~~~
:-: ![](https://img.kancloud.cn/2b/21/2b21813c8540c2452745491e89ab618c_855x213.png =400x)
  注意,grid-auto-flow是一个网格流属性,可让网格项按列排序,后文第五节会重点讲解。
## 四、网格区域
  通过grid-template-areas属性能够以可视化的方式声明网格布局,其值是用空格或换行符分隔的字符串列表,每段字符串又是以空格分隔的自定义标识符,如下所示。
~~~css
div {
grid-template-areas: "a b b"
"a . c";
}
~~~
  每个标识符表示一个网格单元,注意,组合在一起的形状必须得是矩形。当只需要占位时,可以使用点号(.)创建匿名单元。
  为了将网格项与网格区域关联,需要使用grid-area属性。通过它来引用命名好的网格区域,如下所示,grid-area的属性值就是grid-template-areas属性中的标识符,效果如下图所示。
~~~html
<style>
.a {
grid-area: a;
}
.b {
grid-area: b;
}
.c {
grid-area: c;
}
</style>
<div>
<section class="a">a</section>
<section class="b">b</section>
<section class="c">c</section>
</div>
~~~
:-: ![](https://img.kancloud.cn/6b/b9/6bb98a59c2791a99446d9409c95e199d_855x213.png =400x)
## 五、网格流
  网格流可由grid-auto-flow属性控制,它分为两种填充方式:逐行和逐列,并且两者都可通过稠密模式更高效地占用网格单元。
  在下面的示例中,第一个div元素中的网格项会先填满一行再换到下一行,效果如下图的左侧;第二个div元素中的网格项会先填满一列再换到下一列,效果如下图的右侧。
~~~html
<style>
.row {
grid-auto-flow: row;
}
.column {
grid-auto-flow: column;
}
</style>
<div class="row">
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
<section>5</section>
<section>6</section>
</div>
<div class="column">
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
<section>5</section>
<section>6</section>
</div>
~~~
:-: ![](https://img.kancloud.cn/4f/77/4f77b96d5f0be498130a81676de0db69_855x213.png =400x)
  grid-auto-flow属性默认是稀疏模式,而稠密模式会尽力找出最前面的空位置。假设网格容器包含三个网格项,其中有两个会占用两个网格单元,样式如下,效果如下图所示,第一个网格项之后的网格单元闲置着。
~~~html
<style>
.across {
grid-column: auto / span 2;
}
</style>
<div class="row">
<section class="across">1</section>
<section class="across">2</section>
<section>3</section>
</div>
~~~
:-: ![](https://img.kancloud.cn/a9/cd/a9cd4583c2742c1c25104e50d26f3580_413x213.png =300x)
  当为网格容器的grid-auto-flow属性添加dense后,就能触发稠密模式,得到的效果如下图所示,第三个网格项会移动到第一个之后。
~~~css
.row {
grid-auto-flow: row dense;
}
~~~
:-: ![](https://img.kancloud.cn/e7/81/e7819ef0855a049b19a3aff7653a5b55_413x213.png =300x)
## 六、间距
  间距(gutter)也叫空距或栏距,用于控制两个网格轨道之间的距离,类似于将网格线加粗,使其具有宽度。
  间距可由grid-row-gap和grid-column-gap两个属性设定,但要注意,现在这两个属性已改名成row-gap和column-gap,它们相当于表格样式中的border-spacing属性。在下面的示例中,为网格容器添加了两个方向的间距,效果如下图所示。
~~~css
div {
row-gap: 10px;
column-gap: 20px;
}
~~~
:-: ![](https://img.kancloud.cn/77/55/7755da4755098838d3729c5d139e9fa0_412x211.png =300x)
  grid-gap是一个简写属性,可将行和列的间距组合在一起定义,下面样式的效果与上图一样。注意,该属性现已改名成gap。
~~~css
div {
gap: 10px 20px;
}
~~~
  顺便说一句,CSS规范提供了一个简写属性:grid,可将上述grid-template-rows、grid-auto-rows、row-gap等属性组合在一起声明。
## 七、对齐方式
  网格布局中的对齐属性与弹性盒中的类似,也是使用下表中的相关属性。
:-: ![](https://img.kancloud.cn/72/c7/72c7e4a745f17e787272b4d376e15605_739x517.png =500x)
**1)对齐网格项**
  justify-self和align-self两个属性适用于单个网格项,它们的默认值都是stretch,其它可选的关键字包括start、end和center等。
  假设有一个两行三列的网格容器,为它的四个网格项分别添加四个不同关键字的justify-self属性,效果如下图所示。
~~~html
<style>
div {
display: grid;
grid-template-rows: repeat(2, 1fr);
grid-template-columns: repeat(3, 1fr);
}
.justify-self-start {
justify-self: start;
}
.justify-self-end {
justify-self: end;
}
.justify-self-center {
justify-self: center;
}
.justify-self-stretch {
justify-self: stretch;
}
</style>
<div>
<section class="justify-self-start">start</section>
<section class="justify-self-center">center</section>
<section class="justify-self-end">end</section>
<section class="justify-self-stretch">stretch</section>
</div>
~~~
:-: ![](https://img.kancloud.cn/c0/85/c08570e3cfef0e68bdf0ddbd15f0f577_813x213.png =400x)
  将这四个关键字赋给align-self属性,再应用到另一个两行三列的网格容器中,得到的效果如下图所示。
:-: ![](https://img.kancloud.cn/92/2e/922ebb8c818ef6037d9f814993c122a8_811x213.png =400x)
  justify-items和align-items两个属性适用于网格容器,它们的默认值也是stretch,可选的关键字与之前的两个属性类似,下面的样式在为之前的div元素(网格容器)添加justify-items属性。
~~~css
div {
justify-items: start;
}
~~~
**2)对齐网格轨道**
  justify-content和align-content两个属性适用于网格容器,可用的关键字包括start、end、center、space-between和space-around等。
  下图展示了这五个关键字赋给justify-content属性后,再分别应用于网格容器的效果。
:-: ![](https://img.kancloud.cn/51/fb/51fb79f421e6841d71fe3e57d4904e45_1600x562.png =800x)
  下图展示了这五个关键字赋给align-content属性后,再分别应用于网格容器的效果。
:-: ![](https://img.kancloud.cn/17/6c/176c28a59f524066353d831bdee6c6b0_1600x564.png =800x)
## 八、排序
  在网格布局中,也可以像弹性盒那样使用order属性调整网格项的顺序。注意,order属性作用于网格项,其值是一个整数,包括零和负数。在下面的示例中,将第一个和第三个section元素调换了次序,效果如下图所示。
~~~html
<style>
.first {
order: 1;
}
.second {
order: 2;
}
.third {
order: 3;
}
</style>
<div>
<section class="third">1</section>
<section class="second">2</section>
<section class="first">3</section>
</div>
~~~
:-: ![](https://img.kancloud.cn/9a/b2/9ab29fe716762f40c56fda2405433390_410x103.png)
*****
> 原文出处:
[博客园-CSS躬行记](https://www.cnblogs.com/strick/category/1667864.html)
[知乎专栏-CSS躬行记](https://zhuanlan.zhihu.com/pwcss)
已建立一个微信前端交流群,如要进群,请先加微信号freedom20180706或扫描下面的二维码,请求中需注明“看云加群”,在通过请求后就会把你拉进来。还搜集整理了一套[面试资料](https://github.com/pwstrick/daily),欢迎浏览。
![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200)
推荐一款前端监控脚本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不仅能监控前端的错误、通信、打印等行为,还能计算各类性能参数,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、扩展运算符和剩余参数
- 3、解构
- 4、模板字面量
- 5、对象字面量的扩展
- 6、Symbol
- 7、代码模块化
- 8、数字
- 9、字符串
- 10、正则表达式
- 11、对象
- 12、数组
- 13、类型化数组
- 14、函数
- 15、箭头函数和尾调用优化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、类
- 21、类的继承
- 22、Promise
- 23、Promise的静态方法和应用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基础实践
- 3、WebRTC视频通话
- 4、Web音视频基础
- CSS进阶
- 1、CSS基础拾遗
- 2、伪类和伪元素
- 3、CSS属性拾遗
- 4、浮动形状
- 5、渐变
- 6、滤镜
- 7、合成
- 8、裁剪和遮罩
- 9、网格布局
- 10、CSS方法论
- 11、管理后台响应式改造
- React
- 1、函数式编程
- 2、JSX
- 3、组件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表单
- 8、样式
- 9、组件通信
- 10、高阶组件
- 11、Redux基础
- 12、Redux中间件
- 13、React Router
- 14、测试框架
- 15、React Hooks
- 16、React源码分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基础
- 4、webpack进阶
- 5、Git
- 6、Fiddler
- 7、自制脚手架
- 8、VSCode插件研发
- 9、WebView中的页面调试方法
- Vue.js
- 1、数据绑定
- 2、指令
- 3、样式和表单
- 4、组件
- 5、组件通信
- 6、内容分发
- 7、渲染函数和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、数据类型
- 2、接口
- 3、类
- 4、泛型
- 5、类型兼容性
- 6、高级类型
- 7、命名空间
- 8、装饰器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系统和网络
- 3、命令行工具
- 4、自建前端监控系统
- 5、定时任务的调试
- 6、自制短链系统
- 7、定时任务的进化史
- 8、通用接口
- 9、微前端实践
- 10、接口日志查询
- 11、E2E测试
- 12、BFF
- 13、MySQL归档
- 14、压力测试
- 15、活动规则引擎
- 16、活动配置化
- 17、UmiJS版本升级
- 18、半吊子的可视化搭建系统
- 19、KOA源码分析(上)
- 20、KOA源码分析(下)
- 21、花10分钟入门Node.js
- 22、Node环境升级日志
- 23、Worker threads
- 24、低代码
- 25、Web自动化测试
- 26、接口拦截和页面回放实验
- 27、接口管理
- 28、Cypress自动化测试实践
- 29、基于Electron的开播助手
- Node.js精进
- 1、模块化
- 2、异步编程
- 3、流
- 4、事件触发器
- 5、HTTP
- 6、文件
- 7、日志
- 8、错误处理
- 9、性能监控(上)
- 10、性能监控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 监控系统
- 1、SDK
- 2、存储和分析
- 3、性能监控
- 4、内存泄漏
- 5、小程序
- 6、较长的白屏时间
- 7、页面奔溃
- 8、shin-monitor源码分析
- 前端性能精进
- 1、优化方法论之测量
- 2、优化方法论之分析
- 3、浏览器之图像
- 4、浏览器之呈现
- 5、浏览器之JavaScript
- 6、网络
- 7、构建
- 前端体验优化
- 1、概述
- 2、基建
- 3、后端
- 4、数据
- 5、后台
- Web优化
- 1、CSS优化
- 2、JavaScript优化
- 3、图像和网络
- 4、用户体验和工具
- 5、网站优化
- 6、优化闭环实践
- 数据结构与算法
- 1、链表
- 2、栈、队列、散列表和位运算
- 3、二叉树
- 4、二分查找
- 5、回溯算法
- 6、贪心算法
- 7、分治算法
- 8、动态规划
- 程序员之路
- 大学
- 2011年
- 2012年
- 2013年
- 2014年
- 项目反思
- 前端基础学习分享
- 2015年
- 再一次项目反思
- 然并卵
- PC网站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端学习之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 日志
- 2020