CSS Grid Layout(下称网格布局)是目前 css 可支持的最强大的布局系统。在 web 开发早期,开发者通常通过表格、浮动和定位等方式来对网页进行布局,严格意义上来说,这些方法都是以 hack 的方式来完成的,而且遗留了很多无法解决的问题,比如垂直居中。随着 Flexbox 逐步得到支持,网页布局工作得到了明显的改善。但是,Flexbox 也有明显的缺点,就是它只能完成一维布局,即只能完成行或者列的布局,当页面涉及到二维布局时,开发者往往需要使用多个 Flexbox 来完成。网格布局是一个二维布局系统,它可以很好的解决 Flexbox 无法解决的问题。

基本概念

在深入介绍网格布局的使用方法之前,先来了解一些必要的概念。

  • 网格容器(Grid Container):网格布局的顶层容器。
  • 网格元素(Grid Item):网格布局中的元素,注意,网格元素是网格容器的直接后代元素。
  • 网格线(Grid Line):网格系统中区分行列的线。
  • 网格轨迹(Grid Track):两个相邻网格线之间的区域。
  • 网格单元(Grid Cell):两个相邻行线和两个相邻列线框定的区域。
  • 网格区域(Grid Area):四个网格线(两行两列)之间的区域。一个网格区域可包含多个网格单元。

网格容器相关属性

display

该属性定义一个网格容器,并建立一个网格格式化上下文(grid formatting context)。该属性取值如下:

  • grid 建立一个块级网格
  • inline-grid 建立一个行内网格
  • subgrid 当网格容器本身是一个网格元素(网格嵌套)时使用,并指定使用其父元素的网格轨迹来布局。
.container {
  display: grid | inline-grid | subgrid;
}
1
2
3

注意,column、float、clear 和 vertical-align 对网格容器无影响。

grid-template-rows 和 grid-template-columns

这两个属性定义网格的行和列,取值为一个由空格分割的值列表。值表示轨迹(track)的大小,空格表示网格线。取值如下:

  • < track-size > 具体的长度、百分比或者是通过 fr 单位表示的对空白空间的占比
  • < line-name > 任意指定的线名称,线名称用中括号包裹,如 [line-1]
.container {
  grid-template-columns: <track-size> ... | <line-name> <track-size> ...;
  grid-template-rows: <track-size> ... | <line-name> <track-size> ...;
}
1
2
3
4

当未指定网格线名称时,线名称按序号自动确定,如:

.container {
  grid-template-columns: 40px 50px auto 50px 40px;
  grid-template-rows: 25% 100px auto;
}
1
2
3
4

IMAGE 也可以指定网格线的名称,如:

.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
4

IMAGE 一条网格线可以有多个名字,如:

.container {
  grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end];
}
1
2
3

第二条线有两个名字,row1-end 和 row2-start。 如果定义中存在多个重复的情况,可以通过如下方式快速完成:

.container {
  grid-template-columns: repeat(3, 20px [col-start]) 5%;
}
1
2
3

等同于:

.container {
  grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start] 5%;
}
1
2
3

下面这个例子,等同于每个元素占用 1/3 容器的宽度。

.container {
  grid-template-columns: 1fr 1fr 1fr;
}
1
2
3

fr 的计算是除去容器中无法伸缩的元素占用的空间以后的空白空间。比如:

.container {
  grid-template-columns: 1fr 50px 1fr 1fr;
}
1
2
3

grid-template-areas

该属性定义网格布局的模板,通过使用网格元素中 grid-area 属性定义的名字,定义网格布局的结构。两个重复的 grid-area 会合并成一个占两倍空间的 grid-area。取值如下:

  • < grid-area-name > 网格元素中通过 grid-area 属性指定的名字
  • . 点号表示一个空的网格单元
  • none 没有定义网格区域
.container {
  grid-template-areas:
    "<grid-area-name> | . | none | ..."
    "...";
}
1
2
3
4
5

比如:

.item-a {
  grid-area: header;
}
.item-b {
  grid-area: main;
}
.item-c {
  grid-area: sidebar;
}
.item-d {
  grid-area: footer;
}
.container {
  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";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

IMAGE

申明中的每一行需要保证有相同的网格单元数量。网格区域的开始和结束网格线根据网格区域自动生成,如网格区域名为 foo,则开始和结束网格线为 foo-start 和 foo-end。

grid-template

该属性为 grid-template-rows, grid-template-columns, 和 grid-template-areas 的快捷写法。取值为:

  • none 设置三个属性值为初始值。
  • subgrid 设置 grid-template-rows 和 grid-template-columns 为 subgrid,设置 grid-template-areas 为初始值。
  • < grid-template-rows > / < grid-template-columns > 设置 grid-template-rows 和 grid-template-columns 为指定值,设置 grid-template-areas 为 none。
.container {
  grid-template: none | subgrid | <grid-template-rows> / <grid-template-columns>;
}
1
2
3

还有一种同时设置三种属性的写法:

.container {
  grid-template:
    [row1-start] "header header header" 25px [row1-end]
    [row2-start] "footer footer footer" 25px [row2-end]
    / auto 50px auto;
}
1
2
3
4
5
6

等同于

.container {
  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";
}
1
2
3
4
5
6
7

grid-row-gap 和 grid-column-gap

这两个属性指定网格线的大小,即网格行与行、列与列之间间隔的宽度。取值如下:

  • < line-size > 具体的长度。

比如:

.container {
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px;
  grid-column-gap: 10px;
  grid-row-gap: 15px;
}
1
2
3
4
5
6

IMAGE

grid-gap

该属性为 grid-row-gap 和 grid-column-gap 的快捷写法。取值:

  • < grid-row-gap > < grid-column-gap > 具体的长度。
.container {
  grid-gap: <grid-row-gap> <grid-column-gap>;
}
1
2
3

比如:

.container {
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px;
  grid-gap: 10px 15px;
}
1
2
3
4
5

justify-items

网格元素沿行方向的对其方式。类似于 Flexbox。取值为:

  • start 左对齐
  • end 右对齐
  • center 居中对齐
  • stretch 拉伸对齐,默认值
.container {
  justify-items: start | end | center | stretch;
}
1
2
3

如:

.container {
  justify-items: start;
}
1
2
3

IMAGE

.container {
  justify-items: end;
}
1
2
3

IMAGE

.container {
  justify-items: center;
}
1
2
3

IMAGE

.container {
  justify-items: stretch;
}
1
2
3

IMAGE

align-items

网格元素沿列方向的对其方式。类似于 Flexbox。取值为:

  • start 上对齐
  • end 下对齐
  • center 居中对齐
  • stretch 拉伸对齐,默认值
.container {
  align-items: start | end | center | stretch;
}
1
2
3

如:

.container {
  align-items: start;
}
1
2
3

IMAGE

.container {
  align-items: end;
}
1
2
3

IMAGE

.container {
  align-items: center;
}
1
2
3

IMAGE

.container {
  align-items: stretch;
}
1
2
3

IMAGE

justify-content

该属性用于当所有网格元素的总尺寸小于网格容器的尺寸时的沿行方向的对齐方式。取值:

  • start 网格容器的最左端
  • end 网格容器的最右端
  • center 网格容器的中央
  • stretch 拉伸填满网格容器
  • space-around 网格元素间的间距相等,网格元素与网格容器两端的间距为元素间间距的一半。
  • space-between 网格元素间的间距相等,网格元素与网格容器两端的间距为零。
  • space-evenly 所有间距相等。
.container {
  justify-content: start | end | center | stretch | space-around | space-between
    | space-evenly;
}
1
2
3
4

如:

.container {
  justify-content: start;
}
1
2
3

IMAGE

.container {
  justify-content: end;
}
1
2
3

IMAGE

.container {
  justify-content: center;
}
1
2
3

IMAGE

.container {
  justify-content: stretch;
}
1
2
3

IMAGE

.container {
  justify-content: space-around;
}
1
2
3

IMAGE

.container {
  justify-content: space-between;
}
1
2
3

IMAGE

.container {
  justify-content: space-evenly;
}
1
2
3

IMAGE

align-content

该属性用于当所有网格元素的总尺寸小于网格容器的尺寸时的沿列方向的对齐方式。取值:

  • start 网格容器的最上端
  • end 网格容器的最下端
  • center 网格容器的中央
  • stretch 拉伸填满网格容器
  • space-around 网格元素间的间距相等,网格元素与网格容器两端的间距为元素间间距的一半。
  • space-between 网格元素间的间距相等,网格元素与网格容器两端的间距为零。
  • space-evenly 所有间距相等。
.container {
  align-content: start | end | center | stretch | space-around | space-between |
    space-evenly;
}
1
2
3
4

如:

.container {
  align-content: start;
}
1
2
3

IMAGE

.container {
  align-content: end;
}
1
2
3

IMAGE

.container {
  align-content: center;
}
1
2
3

IMAGE

.container {
  align-content: stretch;
}
1
2
3

IMAGE

.container {
  align-content: space-around;
}
1
2
3

IMAGE

.container {
  align-content: space-between;
}
1
2
3

IMAGE

.container {
  align-content: space-evenly;
}
1
2
3

IMAGE

grid-auto-rows 和 grid-auto-columns

这两个属性设置自动生成的网格轨迹(隐式网格轨迹)的大小。通常当我们设置的行和列超过定义的网格时,会产生隐式网格轨迹。

  • < track-size > 确定长度、百分比或者是通过 fr 单位表示的对空白空间的占比
.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

IMAGE 此时设置:

.item-a {
  grid-column: 1 / 2;
  grid-row: 2 / 3;
}
.item-b {
  grid-column: 5 / 6;
  grid-row: 2 / 3;
}
1
2
3
4
5
6
7
8

grid-column 和 grid-row 的定义参考下文。

IMAGE

因为我们定义的行和列超出了网格容器定义的网格,此时会生成宽度为零的网格轨迹。对网格容器添加如下样式:

.container {
  grid-auto-columns: 60px;
}
1
2
3

IMAGE

grid-auto-flow

当网格元素未指定排列方式时,网格容器默认的自动排列方式。取值:

  • row 自动沿行排列,必要情况下会添加新行
  • column 自动沿列排列,必要情况下会添加新列
  • dense 尽可能的填补之前布局的空白,可能会导致元素顺序发生改变
.container {
  grid-auto-flow: row | column | row dense | column dense;
}
1
2
3

如,有如下代码:

<section class="container">
  <div class="item-a">item-a</div>
  <div class="item-b">item-b</div>
  <div class="item-c">item-c</div>
  <div class="item-d">item-d</div>
  <div class="item-e">item-e</div>
</section>
1
2
3
4
5
6
7

样式定义如下:

.container {
  display: grid;
  grid-template-columns: 60px 60px 60px 60px 60px;
  grid-template-rows: 30px 30px;
  grid-auto-flow: row;
}
.item-a {
  grid-column: 1;
  grid-row: 1 / 3;
}
.item-e {
  grid-column: 5;
  grid-row: 1 / 3;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

未设置排列方式的元素排列如下:

IMAGE

修改容器样式:

.container {
  display: grid;
  grid-template-columns: 60px 60px 60px 60px 60px;
  grid-template-rows: 30px 30px;
  grid-auto-flow: column;
}
1
2
3
4
5
6

IMAGE

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 为他们的初始值。取值:

  • none 设置所有属性为初始值。
  • < grid-template-rows > / < grid-template-columns > 设置 grid-template-rows 和 grid-template-columns 为指定值,其他属性为初始值。
  • < grid-auto-flow > [< grid-auto-rows > [/ < grid-auto-columns >]] 设置 grid-auto-flow, grid-auto-rows 和 grid-auto-columns 的值,如果 grid-auto-columns 省略,则使用 grid-auto-rows,如果两个都省略,则使用初始值。
.container {
  grid: none | < grid-template-rows > / < grid-template-columns > | < grid-auto-flow > [< grid-auto-rows > [/ < grid-auto-columns >]];
}
1
2
3

如:

.container {
  grid: 200px auto / 1fr auto 1fr;
}
1
2
3

等同于

.container {
  grid-template-rows: 200px auto;
  grid-template-columns: 1fr auto 1fr;
  grid-template-areas: none;
}
1
2
3
4
5
.container {
  grid: column 1fr / auto;
}
1
2
3

等同于

.container {
  grid-auto-flow: column;
  grid-auto-rows: 1fr;
  grid-auto-columns: auto;
}
1
2
3
4
5

还有一种快捷写法为:

.container {
  grid:
    [row1-start] "header header header" 1fr [row1-end]
    [row2-start] "footer footer footer" 25px [row2-end]
    / auto 50px auto;
}
1
2
3
4
5
6

等同于:

.container {
  grid-template-areas:
    "header header header"
    "footer footer footer";
  grid-template-rows: [row1-start] 1fr [row1-end row2-start] 25px [row2-end];
  grid-template-columns: auto 50px auto;
}
1
2
3
4
5
6
7

网格元素相关属性

grid-row-start、grid-row-end、grid-column-start、grid-column-end

这四个属性指定网格元素在网格中的具体位置。grid-column-start/grid-row-start 指定开始位置, grid-column-end/grid-row-end 指定结束位置。取值:

  • < line > 具体的网格线,可以是数字或者网格线名称
  • span < number > 跨越指定数量的网格轨迹
  • span < name > 跨越区域直到遇到指定名称的网格线
  • auto 自动排列
.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
}
1
2
3
4
5
6

如:

.item-a {
  grid-column-start: 2;
  grid-column-end: five;
  grid-row-start: row1-start;
  grid-row-end: 3;
}
1
2
3
4
5
6

IMAGE

.item-b {
  grid-column-start: 1;
  grid-column-end: span col4-start;
  grid-row-start: 2;
  grid-row-end: span 2;
}
1
2
3
4
5
6

IMAGE

如果 grid-column-end 和 grid-row-end 未指定,默认跨越一个网格轨迹。网格元素允许重叠,可以通过 z-index 控制。

grid-row 和 grid-column

grid-row-start + grid-row-end 和 grid-column-start + grid-column-end 的快捷写法。取值:

  • < start-line > / < end-line > 取值与非快捷写法的取值相同。
.item {
  grid-column: <start-line> / <end-line> | <start-line> / span <value>;
  grid-row: <start-line> / <end-line> | <start-line> / span <value>;
}
1
2
3
4

如:

.item-c {
  grid-column: 3 / span 2;
  grid-row: third-line / 4;
}
1
2
3
4

IMAGE

grid-area

该属性指定网格元素的名字,这样网格元素就可以被 grid-template-areas 引用。同时,该属性也可以被用作 grid-row-start + grid-column-start + grid-row-end + grid-column-end 的更加快捷的写法。取值:

  • < name > 名称,可被 grid-template-areas 引用。
  • < row-start> / < column-start> / < row-end> / < column-end> 数字或者网格线的名字
.item {
  grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;
}
1
2
3

如:

.item-d {
  grid-area: 1 / col4-start / last-line / 6;
}
1
2
3

IMAGE

justify-self

该属性指定网格元素沿行方向的对齐方式。取值:

  • start 左对齐
  • end 右对齐
  • center 居中对齐
  • stretch 拉伸,默认值
.item {
  justify-self: start | end | center | stretch;
}
1
2
3

如:

.item-a {
  justify-self: start;
}
1
2
3

IMAGE

.item-a {
  justify-self: end;
}
1
2
3

IMAGE

.item-a {
  justify-self: center;
}
1
2
3

IMAGE

.item-a {
  justify-self: stretch;
}
1
2
3

IMAGE

align-self

该属性指定网格元素沿列方向的对齐方式。取值:

  • start 上对齐
  • end 下对齐
  • center 居中对齐
  • stretch 拉伸,默认值
.item {
  align-self: start | end | center | stretch;
}
1
2
3

如:

.item-a {
  align-self: start;
}
1
2
3

IMAGE

.item-a {
  align-self: end;
}
1
2
3

IMAGE

.item-a {
  align-self: center;
}
1
2
3

IMAGE

.item-a {
  align-self: stretch;
}
1
2
3

IMAGE

参考链接

关注微信公众号,获取最新推送~

加微信,深入交流~