display: grid 指北
display: flex
Flexible Box 模型,通常被称为 flexbox,是一种一维的布局模型。它给 flexbox 的子元素之间提供了强大的空间分布和对齐能力。
说 flexbox 是一种一维的布局,是因为一个 flexbox 一次只能处理一个维度上的元素布局,一行或者一列。作为对比的是另外一个二维布局 CSS Grid Layout,可以同时处理行和列上的布局。
想要了解更多关于 display: flex
的信息,请参考MDN
下面三个小游戏可以帮你更快了解 Flex 布局的 核心概念:
网格布局:CSS Grid Layout
CSS Grid Layout(中文翻译:网格布局,也叫 CSS Grid 或 Grid) 引入了二维网格布局系统,可用于布局页面主要的区域布局或小型组件。
网格是一组相交的水平线和垂直线,它定义了网格的列和行。
浏览器支持性
术语
- Grid Container:网格容器
- Grid Item/Cell:网格元素
- Grid Line:网格线
- Grid Track:一行或一列
- Grid Area: 一块区域(多个Cell组成的矩形)
网格容器
在元素上声明
display:grid
或display:inline-grid
可以创建一个网格容器。一旦这样做,这个元素的所有直系子元素将成为网格元素。grid-template-columns
grid-template-rows
使用空格分隔的值列表定义网格的列
grid-template-columns
和行grid-template-rows
。这些值代表轨道大小,它们之间的空间代表网格线。
Values:
<track-size> – 长度 / 百分比 / fr
<line-name> – 网格线别名1
2
3
4
5
6
7
8
9
10
11
12
13
14.container {
grid-template-columns: ... ...;
/* e.g.
1fr 1fr
minmax(10px, 1fr) 3fr
repeat(5, 1fr)
50px auto 100px 1fr
*/
grid-template-rows: ... ...;
/* e.g.
min-content 1fr min-content
100px 1fr max-content
*/
}网格线自动从 1 开始命名(-1为最后一根网格线,以此类推)
可以手动指定别名:
1
2
3
4.container {
grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}同一根网格线可以有两个别名:
1
2
3.container {
grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end];
}repeat
如果以相同的模式定义网格的行或列,可以使用repeat
语法:1
2
3
4
5.container {
grid-template-columns: repeat(3, 20px [col-start]);
// 等价于
grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start];
}fr
fr
用来定义网格轨道大小的弹性系数。 每个网格轨道会按比例分配剩余的可用空间。当外层用一个 minmax() 表示时,它将是一个自动最小值(即 minmax(auto, <flex>) ) .1
2
3
4
5
6.container {
grid-template-columns: 1fr 1fr 1fr;
// 也可以混合书写,这种模式下,计算的基数 = 父元素宽度 - 所有非弹性轨道的宽度
grid-template-columns: 1fr 50px 1fr 1fr;
}
grid-template-areas
用来定义网格区域 Grid areas
Values:<grid-area-name> : 网格区域的名称
. 表示空的网格单元格
none
: 没有定义网格区域Examples:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22.container {
display: grid;
grid-template-columns: 50px 50px 50px 50px;
grid-template-rows: auto;
grid-template-areas:
"header header header header"
"main main . sidebar"
"footer footer footer footer";
}
.item-a {
grid-area: header;
}
.item-b {
grid-area: main;
}
.item-c {
grid-area: sidebar;
}
.item-d {
grid-area: footer;
}以上代码会创建一个 3 × 4 的网格布局:
网格布局中的每一行包含的列数是相同的
可以使用
.
声明空网格元素,多个连续的...
仍然代表一个空网格元素注意,这里没有使用网格线别名语法命名行,而是使用区域命名。
当使用此语法时,区域两端的行实际上是自动命名的。如果网格区域的名称是 foo,那么该区域的起始行和起始列行的名称将是 foo-start,其最后一行和最后一列行的名称将是 foo-end。也就是某些行可能有多个名称,例如上面示例中的最左边的行,它将有三个名称: header-start、 main-start 和 footer-start。
grid-template
属性简写,用于同时定义 网格的行、列与分区所简写属性:
grid-template-areas
、grid-template-rows
、grid-template-columns
Values:
none
关键词,设上文所简写属性为none
,即恢复默认设置。行列隐式生成,grid-auto-rows
与grid-auto-columns
定其尺寸。<grid-template-rows> / <grid-template-columns>
指定grid-template-rows
与grid-template-columns
的值,并设grid-template-areas
为none
。[ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <explicit-track-list> ]?
将grid-template-areas
设置为<string>
将grid-template-rows
设置为<string>后面的<track-size>(为缺失的大小填充auto
)
在每个<track-size>之前/之后定义的轨道中拼接,
将grid-template-columns
设置为斜杠后指定的轨道列表(未指定则为none
)。第三个写法较为复杂,可参考:MDN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19.container1 {
grid-template: none | <grid-template-rows> / <grid-template-columns>;
}
// 更复杂的语法
.container2 {
grid-template:
[row1-start] "header header header" 25px [row1-end]
[row2-start] "footer footer footer" 25px [row2-end]
/ auto 50px auto;
}
// 等价于
.container3 {
grid-template-rows: [row1-start] 25px [row1-end row2-start] 25px [row2-end];
grid-template-columns: auto 50px auto;
grid-template-areas:
"header header header"
"footer footer footer";
}由于
grid-template
不会重置隐式网格属性(grid-auto-columns
、grid-auto-rows
和grid-auto-flow
)多数情况下是符合预期的。使用grid
属性可以简写更多属性,参考MDN
column-gap
|grid-column-gap
,row-gap
|grid-row-gap
用来设置元素列(column-gap
)或行(row-gap
)之间的间隔 (gutter) 大小。
Values:<length> 定义行/列之间的间隔大小,非负数。
<percentage> 定义列之间的间隔大小,非负数的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16.container {
/* standard */
column-gap: <line-size>;
row-gap: <line-size>;
/* old */
grid-column-gap: <line-size>;
grid-row-gap: <line-size>;
}
.container {
grid-template-columns: 100px 50px 100px;
grid-template-rows: 80px auto 80px;
column-gap: 10px;
row-gap: 15px;
}间隔只会在列/行之间出现,不回出现在最外层元素与容器之间
gap
|grid-gap
, 简写形式1
2
3
4
5
6
7
8
9
10
11
12
13.container {
/* standard */
gap: <grid-row-gap> <grid-column-gap>;
/* old */
grid-gap: <grid-row-gap> <grid-column-gap>;
}
.container {
grid-template-columns: 100px 50px 100px;
grid-template-rows: 80px auto 80px;
// 如果只提供一个值,则两个属性会被设置为相同值
gap: 15px 10px;
}
justify-items
,align-items
定义网格元素在 行(justify-items
) 或 列(align-items
) 方向上的对齐方式1
2
3.container {
justify-items: start | end | center | stretch;
}justify-items
四个取值的效果展示:该属性可被网格元素的 `justify-self` 属性重置。
align-items
同理,只是方向换成了列,增加了一个值:baseline
,也可被网格元素的align-self
属性重置place-items
: 两个属性的简写,<align-items> / <justify-items>,如果只提供一个值,则同时设置两个属性。justify-content
,align-content
如果网格元素的总宽度比网格容器宽度小(所有元素都使用非弹性宽度指定,px),这种情况下,可以使用justify-content
指定子元素的分布方式Values:
start
end
center
stretch
space-around: 在每个网格项目之间平均分配剩余空间,在网格容器与外层元素中间分配一半空间
space-between: 在每个网格项目之间平均分配剩余空间,在网格容器与外层元素中间不分配空间
space-evenly: 在每个网格项目之间(包括网格容器与外层元素中间)平均分配剩余空间
align-content
同理,只是方向换成了列。place-content
: 简写形式,<align-content> / <justify-content>, 只提供一个值时表示同时设置两个属性。
grid-auto-columns
,grid-auto-rows
grid-auto-columns
指定隐式创建的网格纵向轨道(列)的宽度。
grid-auto-rows
指定隐式创建的网格横向轨道(行)的宽度。Values:
<track-size> – length / percentage / fr
1
2
3
4.container {
grid-auto-columns: <track-size> ...;
grid-auto-rows: <track-size> ...;
}假设我们有如下网格容器布局:
1
2
3
4.container {
grid-template-columns: 60px 60px;
grid-template-rows: 90px 90px;
}以及如下的网格元素:
1
2
3
4
5
6
7
8.item-a {
grid-column: 1 / 2;
grid-row: 2 / 3;
}
.item-b {
grid-column: 5 / 6;
grid-row: 2 / 3;
}让
item-b
放置在第 5 列,直接使用了一个未定义的网格轨道,隐式创建的轨道默认宽度为0,我们可以通过grid-auto-columns
或grid-auto-rows
来手动指定隐式创建的轨道宽度/高度。1
2
3.container {
grid-auto-columns: 60px;
}
grid-auto-flow
控制网格的自动布局算法怎样运作,精确指定在网格中被自动布局的元素怎样排列。Values:
row: 默认值,逐行填充,在必要时增加新行
column: 逐列填充,在必要时增加新列
dense: 该关键字指定自动布局算法使用一种 稠密 堆积算法,如果后面出现了稍小的元素,则会试图去填充网格中前面留下的空白。这样做会填上稍大元素留下的空白,但同时也可能导致原来出现的次序被打乱。
如果省略它,使用一种稀疏算法,在网格中布局元素时,布局算法只会「向前」移动,永远不会倒回去填补空白。这保证了所有自动布局元素「按照次序」出现,即使可能会留下被后面元素填充的空白。dense
与row
|column
组合会形成四种自动布局算法:1
2
3.container {
grid-auto-flow: row | column | row dense | column dense;
}
grid
简写形式,用来设置以下属性:grid-template-rows
grid-template-columns
grid-template-areas
grid-auto-rows
grid-auto-columns
grid-auto-flow
grid-column-gap
grid-row-gap
从易读易写的角度考虑,建议不要合并属性。更多详细信息请参考MDN。
网格元素
float
,display: inline-block
,display: table-cell
,vertical-align
andcolumn-*
不对网格元素生效。
grid-column-start
grid-column-end
grid-row-start
grid-row-end
用来定义网格元素的起始列、结束列、起始行、结束行,从而确定网格元素在网格内的位置。
Values:<number> 起止于第几条网格线。
<name> 自定义的网格线的名称。
span
<number> 表示当前网格会自动跨越指定的网格数量。span
<name> 表示当前网格会自动扩展,直到命中指定的网格线名称。auto
全自动,包括定位,跨度等。1
2
3
4
5
6
7
8
9
10
11
12.item {
grid-column-start: <number> | <name> | span <number> | span <name> | auto;
grid-column-end: <number> | <name> | span <number> | span <name> | auto;
grid-row-start: <number> | <name> | span <number> | span <name> | auto;
grid-row-end: <number> | <name> | span <number> | span <name> | auto;
}
.item-a {
grid-column-start: 2;
grid-column-end: five;
grid-row-start: row1-start;
grid-row-end: 3;
}如果未指定
grid-column-end
/grid-row-end
,网格元素默认会占据一个网格轨道宽度网格元素可以互相重叠,使用
z-index
控制层级顺序
grid-column
grid-row
grid-column
: 简写形式,grid-column-start
+grid-column-end
grid-row
: 简写形式,grid-row-start
+grid-row-end
1
2
3
4
5
6
7
8.item {
grid-column: <start-line> / <end-line> | <start-line> / span <value>;
grid-row: <start-line> / <end-line> | <start-line> / span <value>;
}
.item-c {
grid-column: 3 / span 2;
grid-row: third-line / 4;
}如果只提供一个值,则网格元素默认占据一个轨道宽度/高度
grid-area
指定网格元素放在哪一个区域。区域由网格容器的grid-template-areas
属性定义。
同时也是grid-row-start
+grid-column-start
+grid-row-end
+grid-column-end
的简写形式1
2
3
4
5
6
7
8
9.item {
grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;
}
.item-a {
grid-area: header;
}
.item-b {
grid-area: 1 / col4-start / last-line / 6;
}justify-self
align-self
place-self
与网格容器的justify-items
,align-items
,place-items
属性作用相同,但是仅作用于单一网格元素,不再赘述。
其他
fr
前面已经提过一次,在网格布局中经常会用到fr
单位,了解更多,用来表示占据剩余空间的一部分。例如:1
grid-template-columns: 1fr 3fr;
表示这两列宽度分别为 25% 75%。
设置网格轨道宽度时,除了
px
rem
%
等常用长度单位,还可以使用:min-content
: 最小内容宽度max-content
: 最大内容宽度auto
: 效果与1fr
非常类似,但是遇到相邻轨道fit-content
: 介于min-content
和max-content
之间,尽量占据更多空间。minmax(min, max)
: 大于等于min值,并且小于等于max值。如果max值小于min值,则该值会被视为min值。最大值可以设置为网格轨道系数值<flex> ,但最小值则不行。
repeat
需要定义重复的网格轨道时,使用repeat
可以节省字符:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19.grid {
grid-template-columns:
1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
/* 更简洁: */
grid-template-columns:
repeat(8, 1fr);
/* 当一个网格轨道宽度更复杂时: */
grid-template-columns:
repeat(8, minmax(10px, 1fr));
/* 与关键字结合 */
grid-template-columns:
repeat(auto-fill, minmax(250px, 1fr));
grid-template-columns:
repeat(auto-fit, minmax(250px, 1fr));
}瀑布流布局
网格布局标准支持了一个瀑布流布局语法:1
2
3.grid {
grid-template-rows: masonry;
}但是目前没有浏览器实现,firefox 可以通过 flag 开启支持
动画
根据标准(CSS Grid Layout Module Level 1 specification),以下5个属性可以在动画中使用:grid-gap
,grid-row-gap
,grid-column-gap
: 值为 length, percentage 或 calc 表达式grid-template-columns
,grid-template-rows
: 值为 length, percentage 或 calc 表达式 的列表,并且唯一变化属性是length, percentage 或 calc 表达式具体的支持情况:
Browser (grid-)gap
,(grid-)row-gap
,(grid-)column-gap
grid-template-columns
grid-template-rows
Firefox supported ✅ 53+ supported ✅ 66+ supported ✅ 66+ Safari 12.0 not supported ❌ not supported ❌ not supported ❌ Chrome supported ✅ 66+ not supported ❌ not supported ❌ Chrome for Android 66+, Opera Mini 33+ supported ✅ not supported ❌ not supported ❌ Edge supported ✅ 16+ not supported ❌ not supported ❌
参考链接
写给自己看的display: grid布局教程, by 张鑫旭
CSS Grid 网格布局教程, by 阮一峰
A Complete Guide to Grid, by Chris House
挑战
https://codepen.io/zhangzhen/pen/wvrvvMQ
fork 并完成代码,使页面布局尽可能长得像下图: