简言
CSS 网格布局 (Grid) 是一套二维的页面布局系统, 它的出现将完全颠覆页面布局的传统方式. 传统的 CSS 页面布局 一直不够理想. 包括 table 布局, 浮动, 定位及内联块等方式, 从本质上都是 Hack 的方式, 并且遗漏了一些重要的功能(比如: 垂直居中).Flexbox 的出现部分解决了上述问题, 但 Flex 布局是为了解决简单的一维布局, 适用于页面局部布局. 而 Grid 天然就是为了解决复杂的二维布局而出现的, 适用页面的整体布局. 在实际工作中, Grid 和 Flexbox 不但不矛盾, 而且还能很好的结合使用. 做为 WEB 程序员, 我们在页面布局问题上都付出过努力, 也将不断探索新的方案. 而 Grid 是第一个专门为布局问题而生的 CSS 模块, 我们有理由对 Grid 充满期待.
本文包括 18 个小节, 62 个实例, 完整阅读需要时间 20 分钟以上.
为了获得最佳的阅体验, 可以访问如下格式的教程:
学习 CSS 网格 http://topic.42du.cn/grid
1 网格容器
将属性 display 值设为 grid 或 inline-grid 就创建了一个网格容器, 所有容器直接子结点自动成为网格项目.
1.1 例 1
- grid {
- display: grid;
- }
网格项目按行排列, 网格项目占用整个容器的宽度.
演示程序 http://www.42du.cn/run/122
1.1 例 2
- grid {
- display: inline-grid;
- }
网格项目按行排列, 网格项目宽度由自身宽度决定.
演示程序 http://www.42du.cn/run/123
2 显示网格
属性 grid-template-rows 和
grid-template-columns
用于显示定义网格, 分别用于定义行轨道和列轨道.
2.1 例 3
- grid {
- display: grid;
- grid-template-rows: 50px 100px;
- }
属性 grid-template-rows 用于定义行的尺寸, 即轨道尺寸. 轨道尺寸可以是任何非负的长度值(px,%,em, 等)
网格项目 1 的行高是 50px, 网格项目 2 的行高是 100px.
因为只定义了两个行高, 网格项目 3 和 4 的行高取决于其本身的高度.
演示程序 http://www.42du.cn/run/124
2.2 例 4
- grid {
- display: grid;
- grid-template-columns: 90px 50px 120px;
- }
类似于行的定义, 属性
grid-template-columns
用于定义列的尺寸.
因为定义中只有三列, 所以项目 4,5,6 排在新的一行; 并因为它们位于第 1,2,3 列的轨道上, 所以其宽度等于定义中第 1,2,3 列轨道的宽度.
网格项目的第 1 列, 第 2 列, 第 3 列的宽度分别是 90px, 50px 和 120px .
演示程序 http://www.42du.cn/run/125
2.3 例 5
- grid {
- display: grid;
- grid-template-columns: 1fr 1fr 2fr;
- }
单位 fr 用于表示轨道尺寸配额, 表示按配额比例分配可用空间.
本例中, 项目 1 占 1/4 宽度, 项目 2 占 1/4 宽度, 项目 3 占 1/2 宽度.
演示程序 http://www.42du.cn/run/126
2.4 例 6
- grid {
- display: grid;
- grid-template-columns: 3rem 25% 1fr 2fr;
- }
单位 fr 和其它长度单位混合使用时, fr 的计算基于其它单位分配后的剩余空间.
本例中,
1fr = (容器宽度 - 3rem - 容器宽度的 25%) / 3
演示程序 http://www.42du.cn/run/127
3 轨道的最小最大尺寸设置
函数 minmax()用于定义轨道最小 / 最大边界值.
3.1 例 7
- grid {
- display: grid;
- grid-template-rows: minmax(100px, auto);
- grid-template-columns: minmax(auto, 50%) 1fr 3em;
- }
函数 minmax()接收两个参数: 第一个参数表示最小轨道尺寸, 第二个参数表示最大轨道尺寸. 长度值可以是 auto, 表示轨道尺寸可以根据内容大小进行伸长或收缩.
本例中, 第一行最小高度设置成 100px, 但是最大高度设置成 auto, 表示行高可以根据内容伸长超过 100px.
本例中, 第一列宽度的最大值设置成 50%, 表示其宽度不能超过整个容器宽度的 50%.
演示程序 http://www.42du.cn/run/128
4 重复的网格轨道
函数 repeat()用来定义重复的网格轨道, 尤其适用于有多个相同项目的情况下.
4.1 例 8
- grid {
- display: grid;
- grid-template-rows: repeat(4, 100px);
- grid-template-columns: repeat(3, 1fr);
- }
函数 repeat()接收两个参数: 第一个参数表示重复的次数, 第二个参数表示轨道尺寸.
演示程序 http://www.42du.cn/run/129
4.2 例 9
- grid {
- display: grid;
- grid-template-columns: 30px repeat(3, 1fr) 30px;
- }
函数 repeat()可以用在轨道定义列表当中.
本例中, 第 1 列和第 5 列的宽度是 30px. 函数 repeat()创建了中间 3 列, 每一列宽度都是 1fr.
演示程序 http://www.42du.cn/run/130
5 定义网格间隙
属性 grid-column-gap 和 grid-row-gap 用于定义网格间隙.
网格间隙只创建在行列之间, 项目与边界之间无间隙.
5.1 例 10
- grid {
- display: grid;
- grid-row-gap: 20px;
- grid-column-gap: 5rem;
- }
间隙尺寸可以是任何非负的长度值(px,%,em 等).
演示程序 http://www.42du.cn/run/131
5.2 例 11
- grid {
- display: grid;
- grid-gap: 100px 1em;
- }
属性 grid-gap 是 grid-row-gap 和 grid-column-gap 的简写形式.
第一个值表示行间隙, 第二个值表示列间隙.
演示程序 http://www.42du.cn/run/132
5.3 例 12
- grid {
- display: grid;
- grid-gap: 2rem;
- }
如只有一个值, 则其即表示行间隙, 也表示列间隙.
演示程序 http://www.42du.cn/run/133
6 用网格线编号定位项目
网格线本质上是用来表示网格轨道的开始和结束.
每一条网格线编号都以 1 开始, 以 1 为步长向前编号, 其中包括行列两组网格线.
6.1 例 13
- .item1 {
- grid-row-start: 2;
- grid-row-end: 3;
- grid-column-start: 2;
- grid-column-end: 3;
- }
这是一个 3 行 2 列的网格, 即在行上有 4 条网格线, 在列上有 3 条网格线. 项目 1 利用网格线编号定位在第 2 行第 2 列的位置上.
本例中, 项目只跨越一行一列, 则 grid-row-end 和 grid-column-end 的定义可以省略.
演示程序 http://www.42du.cn/run/134
6.2 例 14
- .item1 {
- grid-row: 2;
- grid-column: 3 / 4;
- }
属性 grid-row 是 grid-row-start 和 grid-row-end 的简写形式.
属性 grid-column 是 grid-column-start 和 grid-column-end 的简写形式.
如果只指定一个值, 它表示
- grid-row/column-start
- .
如果两个值都指定, 第一个表示
grid-row/column-start
, 第二个值表示 grid-row/column-end. 而且你必须用斜杠 (/) 分隔这两个值.
演示程序 http://www.42du.cn/run/135
6.3 例 15
- .item1 {
- grid-area: 2 / 2 / 3 / 3;
- }
属性 grid-area 是 grid-row-start, grid-column-start, grid-row-end 和 grid-column-end 的简写形式.
如果四个值都指定, 则第一个表示 grid-row-start, 第二个表示 grid-column-start, 第三个表示 grid-row-end , 第四个表示 grid-column-end.
演示程序 http://www.42du.cn/run/136
7 网格项目跨越行列
网格项目默认都占用一行和一列, 但可以使用前一节中定位项目的属性来指定项目跨越多行或多列.
7.1 例 16
- .item1 {
- grid-column-start: 1;
- grid-column-end: 4;
- }
通过 grid-column-start 和 grid-column-end 属性值的设置, 使该网格项目跨越多列.
演示程序 http://www.42du.cn/run/137
7.2 例 17
- .item1 {
- grid-row-start: 1;
- grid-row-end: 4;
- }
通过 grid-row-start 和 grid-row-end 属性值的设置, 使该网格项目跨越多行.
演示程序 http://www.42du.cn/run/138
7.3 例 18
- .item1 {
- grid-row: 2 / 5;
- grid-column: 2 / 4;
- }
简写属性 grid-row 和 grid-column 即能用来定位项目, 也能用来使项目跨越多个行列.
演示程序 http://www.42du.cn/run/139
7.4 例 19
- .item1 {
- grid-row: 2 / span 3;
- grid-column: span 2;
- }
关键字 span 用来指定跨越行或列的数量.
演示程序 http://www.42du.cn/run/140
8 网格线命名
当利用属性 grid-template-rows 和
grid-template-columns
定义网格时, 可以同时定义网格线的名称. 网格线名称可以用于定位网格项目.
8.1 例 20
- grid {
- display: grid;
- grid-template-rows: [row-1-start] 1fr [row-2-start] 1fr [row-2-end];
- grid-template-columns: [col-1-start] 1fr [col-2-start] 1fr [col-3-start] 1fr [col-3-end];
- }
用属性 grid-template-rows 和
grid-template-columns
定义网格, 同时定义网格线名称.
为避免混淆, 网格线名称应避免使用规范中的关键字(span 等).
定义网格线名称的方法是要将其放在中括号内([name-of-line]), 并要和网格轨道相对应.
8.2 例 21
- grid {
- display: grid;
- grid-template-rows: [row-start row-1-start] 1fr [row-1-end row-2-start] 1fr [row-2-end row-end];
- grid-template-columns: [col-start] 1fr [col-2-start] 1fr [col-3-start] 1fr [col-end];
- }
可以给同一网格线定义多个名称, 方法就是在中括号内用空格将多个名称分开.
每一个网格线名都可以被引用, 以用来定位网格项目.
9 用网格线名定位项目
利用命名的网格线, 可以很方便地进行项目定位.
9.1 例 22
- .item1 {
- grid-row-start: row-2-start;
- grid-row-end: row-end;
- grid-column-start: col-2-start;
- grid-column-end: col-end;
- }
引用网格线名称不用加中括号.
演示程序 http://www.42du.cn/run/141
9.2 例 23
- .item1 {
- grid-row: row-2-start / row-end;
- grid-column: col-2-start / col-end;
- }
简写属性 grid-row 和 grid-column 也可以利用网格线名称来定位项目.
演示程序 http://www.42du.cn/run/142
10 用同名网格线命名和定位项目
函数 repeat()可以定义同名网格线. 这节省了给每条网格都命名的时间.
10.1 例 24
- grid {
- display: grid;
- grid-template-rows: repeat(3, [row-start] 1fr [row-end]);
- grid-template-columns: repeat(3, [col-start] 1fr [col-end]);
- }
函数 repeat()可以用来定义同名网格线. 这样多个网格线拥有相同的名字.
同名网格线会被分配一个位置编号, 做为其唯一标识.
10.2 例 25
- .item1 {
- grid-row: row-start 2 / row-end 3;
- grid-column: col-start / col-start 3;
- }
用同名网格线来定位项目时, 应注意在网格线名称和编号之间有一个空格.
本例中, 项目 1 的行定位开始于第 2 条名称是 row-start 的网格线, 结束于第 3 条名称是 row-end 的网格线; 列定位开始于第 1 条名称是 col-start 的网格线, 结束于第 3 条名称是 col-start 的网格线.
演示程序 http://www.42du.cn/run/143
11 用网格区域命名和定位项目
如同网格线命名, 可以用属性 grid-template-areas 给网格区域命名. 网格区域名称可以用来定位网格项目.
11.1 例 26
- grid {
- display: grid;
- grid-template-areas: "header header"
- "content sidebar"
- "footer footer";
- grid-template-rows: 150px 1fr 100px;
- grid-template-columns: 1fr 200px;
- }
一组区域名称要放在单引号或双引号内, 每一个名称之间以空格分隔.
每一组名称定义一行, 每一个名称定义一列.
11.2 例 27
- header {
- grid-row-start: header;
- grid-row-end: header;
- grid-column-start: header;
- grid-column-end: header;
- }
网格区域名称可以用在属性 grid-row-start, grid-row-end, grid-column-start, 和 grid-column-end 的值中, 用来定位项目.
11.3 例 28
- footer {
- grid-row: footer;
- grid-column: footer;
- }
网格区域名称也可以用于简写属性 grid-row 和 grid-column 的值中.
11.4 例 29
- aside {
- grid-area: sidebar;
- }
网格区域名称也可以用于简写属性 grid-area 的值中.
演示程序 http://www.42du.cn/run/144
12 隐式网格
隐式网格用来在显式网格之外定位项目. 有时在显示网格中没有足够的空间, 或者是要在显示网格之外定位项目就要用到隐式网格. 这时可以把这些项目放置在隐式网格中.
隐式网格可以通过属性 grid-auto-rows, grid-auto-columns, 和 grid-auto-flow 来定义.
12.1 例 30
- grid {
- display : grid;
- grid-template-rows: 70px;
- grid-template-columns: repeat(2, 1fr);
- grid-auto-rows: 140px;
- }
本例中, 只定一个行轨道, 因此项目 1 和 2 高 70px .
第 2 行轨道有隐式网格自动创建并为项目 3 和 4 分配了空间. 属性 grid-auto-rows 定义了隐式网格的行轨道尺寸, 即项目 3 和 4 的高度是 140px .
演示程序 http://www.42du.cn/run/145
12.2 例 31
- grid {
- display : grid;
- grid-auto-flow: row;
- }
缺省的网格布局方向是行的方向(row).
12.3 例 32
- grid {
- display : grid;
- grid-auto-flow: column;
- }
网格的布局方向可以定义为列的方向(column).
12.4 例 33
- grid {
- display : grid;
- grid-template-columns: 30px 60px;
- grid-auto-flow: column;
- grid-auto-columns: 1fr;
- }
本例中, 我们只定义了两个列轨道的尺寸 30px 和 60px.
隐式网格中自动创建其它列并给项目 3,4,5 分配空间; 分配的空间尺寸是通过属性 grid-auto-columns 定义的.
演示程序 http://www.42du.cn/run/146
13 隐式命名的网格区域
网格线名称可以任意指定, 但分配以 -start 和 -end 结尾的名字有额外的益处, 这样隐式地创建了具名网格区域, 该名称可以用于项目定位.
13.1 例 34
- grid {
- display : grid;
- grid-template-rows: [outer-start] 1fr [inner-start] 1fr [inner-end] 1fr [outer-end];
- grid-template-columns: [outer-start] 1fr [inner-start] 1fr [inner-end] 1fr [outer-end];
- }
本例中, 行和列都有名为 inner-start 和 inner-end 的网格线, 它们隐式地给网格区域分派了名称(inner).
- item1 {
- grid-area: inner;
- }
这样我们就能够直接使用网格区域名来定位, 而不需要再用网格线来定位项目了.
演示程序 http://www.42du.cn/run/147
14 隐式命名的网格线
隐式命名网格线和隐式命名的网格区域的工作原理刚好相反.
14.1 例 35
- grid {
- display : grid;
- grid-template-areas: "header header"
- "content sidebar"
- "footer footer";
- grid-template-rows: 80px 1fr 40px;
- grid-template-columns: 1fr 200px;
- }
定义网格区域时隐式的命名了网格线的名称. 这些网格线的名称是基于区域名加上 - start 或 -end 后缀组成的.
14.2 例 36
- item1 {
- grid-row-start: header-start;
- grid-row-end: content-start;
- grid-column-start: footer-start;
- grid-column-end: sidebar-end;
- }
本例中, header 是通过隐式网格线名称进行定位的.
演示程序 http://www.42du.cn/run/148
15 层叠网格项目
通过项目定位可以使多个项目层叠在一起, 属性 z-index 可以改变层叠项目的层次.
15.1 例 37
- .item-1, .item-2 {
- grid-row-start: 1;
- grid-column-end: span 2;
- }
- .item-1 { grid-column-start: 1; z-index: 1; }
- .item-2 { grid-column-start: 2 }
本例中, 项目 1 和 2 行定位开始于第 1 条行网格线, 并跨越两列.
两个项目都是用网格线编号进行定位. 项目 1 起始于第 1 条列网格线, 项目 2 起始于第 2 条列网格线, 这使得两个项目在第一行中间列发生层叠.
缺省情况下, 项目 2 将层叠于项目 1 之上; 然而, 给项目 1 设置属性 z-index: 1 就使得项目 1 层叠于项目 2 之上.
演示程序 http://www.42du.cn/run/149
15.2 例 38
- .overlay {
- grid-row-start: header-start;
- grid-row-end: content-end;
- grid-column-start: content-start;
- grid-column-end: sidebar-start;
- z-index: 1;
- }
本例中, 利用在 grid-template-areas 定义中的隐式网格线名称, 定位了一个网格项目(overlay), 并将层叠于上层.
演示程序 http://www.42du.cn/run/150
16 网格项目的对齐方式
CSS 的 盒模型对齐模块 https://drafts.csswg.org/css-align/ 补充了 CSS 网格的内容, 网格项目可以按行或列的轴线方向实现多种对齐方式.
属性 justify-items 和 justify-self 以行轴为参照对齐项目, 属性 align-items 和 align-self 以列轴为参照对齐项目.
属性 justify-items 和 align-items 是网格容器的属性, 并支持如下这些值:
- auto
- normal
- start
- end
- center
- stretch
- baseline
- first baseline
- last baseline
16.1 例 39
- .grid {
- grid-template-rows: 80px 80px;
- grid-template-columns: 1fr 1fr;
- grid-template-areas: "content content"
- "content content";
- }
- .item { grid-area: content }
- .grid {
- justify-items: start
- }
在行的轴线起点处对齐.
演示程序 http://www.42du.cn/run/151
16.2 例 40
- grid {
- justify-items: center;
- }
在行的轴线中点处对齐.
演示程序 http://www.42du.cn/run/152
16.3 例 41
- grid {
- justify-items: end;
- }
在行的轴线终点处对齐.
演示程序 http://www.42du.cn/run/153
16.4 例 42
- grid {
- justify-items: stretch;
- }
在行的轴线方向延伸并填满整个区域. stretch 是缺省值.
演示程序 http://www.42du.cn/run/154
16.5 例 43
- grid {
- align-items: start;
- }
在列的轴线起点处对齐.
演示程序 http://www.42du.cn/run/155
16.6 例 44
- grid {
- align-items: center;
- }
在列的轴线中点处对齐.
演示程序 http://www.42du.cn/run/156
16.7 例 45
- grid {
- align-items: end;
- }
在列的轴线终点处对齐.
演示程序 http://www.42du.cn/run/157
16.8 例 46
- grid {
- align-items: stretch;
- }
在列的轴线方向延伸并填满整个区域.
演示程序 http://www.42du.cn/run/158
16.9 例 47
- grid {
- justify-items: center;
- align-items: center;
- }
项目定位于行轴和列轴线的中间位置.
演示程序 http://www.42du.cn/run/159
17 网格项目的对齐方式 2
项目可以用属性 align-self 和 justify-self 定义自己的对齐方式, 并支持如下这些属性值:
- auto
- normal
- start
- end
- center
- stretch
- baseline
- first baseline
- last baseline
17.1 例 48
- .item1 { justify-self: start }
- .item2 { justify-self: center }
- .item3 { justify-self: end }
属性 justify-self 在行的轴线方向定义对齐方式.
演示程序 http://www.42du.cn/run/160
17.2 例 49
- .item1 { align-self: start }
- .item2 { align-self: center }
- .item3 { align-self: end }
属性 align-self 在列的轴线方向定义对齐方式.
演示程序 http://www.42du.cn/run/161
17.3 例 50
- .item1 {
- justify-self: center
- align-self: center
- }
项目 1 定位在行的轴线和列的轴线的中间位置.
演示程序 http://www.42du.cn/run/162
18 网格轨道的对齐方式
在网格容器中, 网格轨道延轴线方向有多种对齐方式.
属性 align-content 用于定义网格轨道延着行的轴线的对齐方式, 而属性 justify-content 用于定义网格轨道沿着列的轴线的对齐方式. 并分别支持如下属性:
- normal
- start
- end
- center
- stretch
- space-around
- space-between
- space-evenly
- baseline
- first baseline
- last baseline
18.1 例 51
- .grid {
- width: 100%;
- height: 300px;
- grid-template-columns: repeat(4, 45px);
- grid-template-rows: repeat(4, 45px);
- grid-gap: 0.5em;
- justify-content: start;
- }
列的轨道在行的轴线起点处对齐. start 是缺省值.
演示程序 http://www.42du.cn/run/163
18.2 例 52
- .grid {
- justify-content: end;
- }
列的轨道在行的轴线终点处对齐.
演示程序 http://www.42du.cn/run/164
18.3 例 53
- .grid {
- justify-content: center;
- }
列的轨道在行的轴线中间处对齐.
演示程序 http://www.42du.cn/run/165
18.4 例 54
- .grid {
- justify-content: space-around;
- }
在每一列的两侧平均分配额外空间.
演示程序 http://www.42du.cn/run/166
18.5 例 55
- .grid {
- justify-content: space-between;
- }
在列与列之间平均分配额外的空间.
演示程序 http://www.42du.cn/run/167
18.6 例 56
- .grid {
- justify-content: space-evenly;
- }
在列与列之间及列与边界之间平均分配额外空间.
演示程序 http://www.42du.cn/run/168
18.7 例 57
- .grid {
- align-content: start;
- }
行的轨道在列的轴线起点处对齐, 属性 start 是缺省值.
演示程序 http://www.42du.cn/run/169
18.8 例 58
- .grid {
- align-content: end;
- }
行的轨道在列的轴线终点处对齐.
演示程序 http://www.42du.cn/run/170
18.9 例 59
- .grid {
- align-content: center;
- }
行的轨道在列的轴线中点处对齐.
演示程序 http://www.42du.cn/run/171
18.10 例 60
- .grid {
- align-content: space-around;
- }
每一行的两侧平均分配额外空间.
演示程序 http://www.42du.cn/run/172
18.11 例 61
- .grid {
- align-content: space-between;
- }
在行与行之间平均分配额外空间.
演示程序 http://www.42du.cn/run/173
18.12 例 62
- .grid {
- align-content: space-evenly;
- }
在行与行之间及行与边界之间平均分配额外空间.
演示程序 http://www.42du.cn/run/174
结语
本教程相对全面地介绍了网格的相关内容, 但这并不是一个完整的技术文档. 想更全面的学习相关内容, 推荐访问 Mozilla 开发者网络 https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout 和 W3C https://www.w3.org/TR/css3-grid-layout/ 的网格文档.
由于能力有限, 翻译中难免错误较多, 还请大家多多谅解!
来源: https://segmentfault.com/a/1190000014690181