css中的grid布局

简介

CSS 网格布局擅长于将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系(前提是HTML生成了这些区域)。
Flex 布局是轴线布局,只能指定”项目”针对轴线的位置,可以看作是一维布局。Grid 布局则是将容器划分成”行”和”列”,产生单元格,然后指定”项目所在”的单元格,可以看作是二维布局。Grid 布局远比 Flex 布局强大。
在Grid布局中,所有css属性分为两类,一类作用到grid容器上,还有一类作用在grid项目上。
如下表格所示:

作用在grid容器上 作用在grid子项上
grid-template-columns
grid-template-rows
grid-template-areas
grid-template
grid-column-gap
grid-row-gap
grid-gap
justify-items
align-items
place-items
justify-content
align-content
place-content
grid-auto-columns
grid-auto-rows
grid-auto-flow
grid
grid-column-start
grid-column-end
grid-row-start
grid-row-end
grid-column
grid-row
grid-area
justify-self
align-self
place-self

作用在grid容器上的CSS属性

基础代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="container">
<div style="background: #00ff00">
1
</div>
<div style="background: #ff0000">
2
</div>
<div style="background: #0000ff; color: #fff">
3
</div>
<div style="background: #ffff00">
4
</div>
<div style="background: #00ffff">
5
</div>
<div style="background: #0f0f0f; color: #fff">
6
</div>
<div style="background: #f0f0f0">
7
</div>
<div style="background: #ff00ff">
8
</div>
<div style="background: #fff000">
9
</div>
<div style="background: #00ff00">
10
</div>
<div style="background: #000fff; color: #fff">
11
</div>
<div style="background: #00ffff">
12
</div>
</div>
</body>
</html>

grid-template-columns和grid-template-rows

容器指定了网格布局以后,接着就要划分行和列。grid-template-columns属性定义每一列的列宽,grid-template-rows属性定义每一行的行高。

1
2
3
4
5
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px 100px;
}

上面的代码会指定一个3列4行的网格,列宽和行高都是100px;
css grid

  • 可以为 px 或者 百分比(%)
  • auto
  • repeat( [ | auto-fill | auto-fit ] , )
  • fr(fraction)是单词fraction的缩写,表示分数
  • max-content、min-content、minmax(min, max)

px和百分比我们就不介绍了。

auto

有时,单元格的大小是固定的,但是容器的大小不确定。如果希望每一行(或每一列)容纳尽可能多的单元格,这时可以使用auto-fill关键字表示自动填充。

1
2
3
4
5
.container {
display: grid;
grid-template-columns: auto 100px 100px;
grid-template-rows: 100px 100px 100px 100px;
}

我们把第一列设置为auto,效果如下:
css grid

repeat()

表示网格轨道的重复部分,以一种更简洁的方式去表示大量而且重复列的表达式。函数接收两个参数,第一个参数是重复的次数,第二个参数是所要重复的值。在第一个基础上改写代码如下:

1
2
3
4
5
.container {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-template-rows: 100px 100px 100px 100px;
}

这个效果和直接写三个100px的效果是一样的。

fr

fr是单词fraction的缩写,表示分数。

  • 先从简单例子看起:
    1
    2
    3
    4
    5
    .container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 100px 100px 100px 100px;
    }

1:1:1,网格宽度三等分,实时效果如下:
css grid

  • 如果有固定尺寸值,则划分剩余空间大小,例如:
    1
    2
    3
    4
    5
    .container {
    display: grid;
    grid-template-columns: 100px 1fr 1fr;
    grid-template-rows: 100px 100px 100px 100px;
    }

css grid
后面两列是grid容器宽度减去100像素后的1/2。

  • 如果和auto混用会如何呢
    1
    2
    3
    4
    5
    .container {
    display: grid;
    grid-template-columns: auto 1fr 1fr;
    grid-template-rows: 100px 100px 100px 100px;
    }

css grid
auto 在和 px、百分比一起用的时候是撑满剩下的空间。但是和fr一起用的时候为内容宽度。

grid-template-areas

grid-template-areas属性是 grid areas 在CSS中的特定命名。
语法

none
网格容器没有定义任何的网格区块(grid areas)。
<string>+
每一个给定的字符串会生成一行,一个字符串中用空格分隔的每一个单元(cell)会生成一列。多个同名的,跨越相邻行或列的单元称为网格区块(grid area)。非矩形的网格区块是无效的。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
<div style="background: #00ff00">
1
</div>
<div style="background: #ff0000">
2
</div>
<div style="background: #0000ff; color: #fff">
3
</div>
<div style="background: #ffff00">
4
</div>

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: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-template-areas:
"头部 头部 头部"
"nav content content"
"nav content content"
"foot foot foot";
}
.container > div:first-child {
grid-area: 头部;
}
.container > div:nth-child(2) {
grid-area: nav;
}
.container > div:nth-child(3) {
grid-area: content;
}
.container > div:last-child {
grid-area: foot;
}

我们的网格区域一定要形成规整的矩形区域,什么L形,凹的或凸的形状都是不支持的,会认为是无效的属性值。
css grid

grid-template

grid-template 是一个简写的CSS属性,用于定义 grid columns, rows 和areas。
语法如下:

1
grid-template: <grid-template-rows> / <grid-template-columns>;

用grid-template实现上面的效果,代码如下:

1
2
3
4
5
6
7
8
9
.container {
display: grid;
grid-template:
"头部 头部 头部" 1fr
"nav content content" 1fr
"nav content content" 1fr
"foot foot foot" 1fr
/ 1fr 1fr 1fr;
}

它实现的效果和上面的一样。

由于grid-template不会重置一些隐式的grid属性(如grid-auto-columnsgrid-auto-rowsgrid-auto-flow),因此,大多数时候,还是推荐使用grid代替grid-template。

grid-column-gap和grid-row-gap、grid-gap

grid-column-gap和grid-row-gap属性用来定义网格中网格间隙的尺寸。你可以理解成田地之间走路的田垄宽度。
语法如下:

1
2
grid-column-gap: 10px; // 水平间隔 10px
grid-row-gap: 10px; // 垂直间隔 10px

代码如下:

1
2
3
4
5
6
7
.container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-column-gap: 10px;
grid-row-gap: 10px;
}

css grid

grid-gap

CSS grid-gap属性是grid-column-gap和grid-row-gap属性的缩写。语法如下:

1
grid-gap: <grid-row-gap> <grid-column-gap>;

实现和上面一样的布局代码如下:

1
2
3
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-gap: 10px 10px;

justify-items、align-items、palce-items

justify-items属性设置单元格内容的水平位置(左中右),align-items属性设置单元格内容的垂直位置(上中下)。
语法如下

1
2
justify-items: start | end | center | stretch;
align-items: start | end | center | stretch;

  • start:对齐单元格的起始边缘。
  • end:对齐单元格的结束边缘。
  • center:单元格内部居中。
  • stretch:拉伸,占满单元格的整个宽度(默认值)。

justify-items 效果参考 张鑫旭大佬的博客
align-items 效果参考 张鑫旭大佬的博客

palce-items

place-items属性是align-items属性和justify-items属性的合并简写形式。
语法

1
place-items: <align-items> <justify-items>;

如果省略第二个值,则浏览器认为与第一个值相等。

justify-content、align-content、place-content

justify-content属性是整个内容区域在容器里面的水平位置(左中右),align-content属性是整个内容区域的垂直位置(上中下)。

justify-content指定了网格元素的水平分布方式。此属性仅在网格总宽度小于grid容器宽度时候有效果。

语法如下:

1
2
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
align-content: start | end | center | stretch | space-around | space-between | space-evenly;

  • start - 对齐容器的起始边框。
  • end - 对齐容器的结束边框。
  • center - 容器内部居中。
  • stretch - 项目大小没有指定时,拉伸占据整个网格容器。
  • space-around - 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍。
  • space-between - 项目与项目的间隔相等,项目与容器边框之间没有间隔。
  • space-evenly - 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔。

正式效果参考如下:
justify-content 效果参考 张鑫旭大佬的博客
align-content 效果参考 张鑫旭大佬的博客

place-content

place-content属性是align-content属性和justify-content属性的合并简写形式。

1
place-content: <align-content> <justify-content>

如果省略第二个值,浏览器就会假定第二个值等于第一个值。

grid-auto-columns、grid-auto-rows

指定任何自动生成的网格轨道(也称为隐式网格轨道)的大小。 当网格项目多于网格中的单元格或网格项目放置在显式网格之外时,将创建隐式轨道。
语法

1
2
grid-auto-columns: <track-size> ...;
grid-auto-rows: <track-size> ...;

grid-auto-columns属性和grid-auto-rows属性用来设置,浏览器自动创建的多余网格的列宽和行高。它们的写法与grid-template-columnsgrid-template-rows完全相同。如果不指定这两个属性,浏览器完全根据单元格内容的大小,决定新增网格的列宽和行高。

示例如划分好的网格是2行 x 2列,但是,3号项目指定在第3行,4号项目指定在第4行。
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  .container {
display: grid;
grid-template-columns: 100px 100px;
grid-template-rows: 100px 100px;
grid-auto-columns: 50px;
grid-auto-rows: 50px;
}
.container div:nth-child(3) {
grid-column: 3;
grid-row: 3;
}
.container div:nth-child(4) {
grid-column: 4;
grid-row: 4;
}

css grid

grid-auto-flow

grid-auto-flow属性控制没有明确指定位置的grid子项的放置方式。比方说定义了一个5*2的10格子,共有5个元素,其中2个元素指定了放在哪个格子里,还有3个则自生自灭排列。此时,这3个元素如何排列就是由grid-auto-flow属性控制的。
语法

1
grid-auto-flow: row | column | row dense | column dense

  • row 默认值。没有指定位置的网格依次水平排列优先。
  • column 没有指定位置的网格依次垂直排列优先。
  • dense dense这个英文是稠密的意思。如果有设置,则表示自动排列启用“密集”打包算法。如果稍后出现的网格比较小,则尝试看看前面有没有合适的地方放置,使网格尽可能稠密紧凑。此属性值仅仅改变视觉顺序,会导致DOM属性和实际呈现顺序不符合,这对于可访问性是不友好的,建议谨慎使用。
    示例请看grid-auto-flow 效果参考 张鑫旭大佬的博客

grid

是下面所有这些CSS属性的缩写集合,grid-template-rows,grid-template-columns,grid-template-areas,grid-auto-rows,grid-auto-columns和grid-auto-flow。
语法:

1
grid: none

none表示设置所有的子属性为初始值。

1
grid: <grid-template>

和grid-template用法一致

1
grid: <grid-template-rows> / [ auto-flow && dense? ] <grid-auto-columns>?

上面就是grid容器上的属性,属性很多不好记,要多练习几遍才能熟练使用。

作用在grid子项上的CSS属性

  • grid-column-start, grid-column-end, grid-row-start和grid-row-end
  • grid-column和grid-row
  • grid-area
  • justify-self、align-self、place-self

grid-column-start, grid-column-end, grid-row-start和grid-row-end

表示grid子项所占据的区域的起始和终止位置,包括水平方向和垂直方向。
语法

1
2
3
4
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

语法中的管道分隔符|表示“或者”的意思,所以别看上面好长,实际上就一个属性值,具体来讲:


  • 起止与第几条网格线。

  • 自定义的网格线的名称。
  • span
    表示当前网格会自动跨越指定的网格数量。
  • span
    表示当前网格会自动扩展,直到命中指定的网格线名称。
  • auto
    全自动,包括定位,跨度等。

普通数字

1
2
3
4
5
6
7
8
9
10
11
  .container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
}
.container div:nth-child(1) {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 3;
}

css grid

网格线的名字

1
2
3
4
5
6
7
8
9
10
11
.container {
display: grid;
grid-template-columns: [第一列] 100px [第二列] 100px [第三列] 100px;
grid-template-rows: [第一行] 100px [第二行] 100px [第三行] 100px;
}
.container div:nth-child(1) {
grid-column-start: 第一列;
grid-column-end: 3;
grid-row-start: 第一行;
grid-row-end: 3;
}

与上面结果相同

span关键字

1
2
3
4
5
6
7
8
9
.container {
display: grid;
grid-template-columns: [第一列] 100px [第二列] 100px [第三列] 100px;
grid-template-rows: [第一行] 100px [第二行] 100px [第三行] 100px;
}
.container div:nth-child(1) {
grid-column-start: span 2;
grid-row-start: span 2;
}

grid-column和grid-row

grid-column属性是grid-column-startgrid-column-end的合并简写形式,grid-row属性是grid-row-start属性和grid-row-end的合并简写形式。
语法

1
2
grid-column: <start-line> / <end-line> | <start-line> / span <value>;
grid-row: <start-line> / <end-line> | <start-line> / span <value>;

改写上面的代码:

1
2
3
4
.container div:nth-child(1) {
grid-column:[第一列]/ span 2;
grid-row-start: [第一行]/ span 2;
}

与上面的实现一样。

grid-area

grid-area表示当前网格所占用的区域。在介绍grid-template-areas属性的时候就演示过该属性,我们使用grid-template-areas属性自定义一些网格区域,然后使用grid-area属性让grid子项指定使用这些区域,就自动进行了区域分布。
grid-areagrid-column/grid-row作用都是grid子项的分布,但grid-area语义要更好,识别度更佳,非常适合具有功能属性的布局区域(如头部,底部),同时,还支持非规则区域。

语法

1
grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;

  • 区域名称。由grid-template-areas属性创建。
  • <row-start> / <column-start> / <row-end> / <column-end> 占据网格区域的纵横起始位置。

改写上面代码:

1
2
3
.container div:nth-child(1) {
grid-area: 1 / 1 / 3 / 3;
}

justify-self、align-self、place-self

justify-self属性设置单元格内容的水平位置(左中右),跟justify-items属性的用法完全一致,但只作用于单个项目。
align-self属性设置单元格内容的垂直位置(上中下),跟align-items属性的用法完全一致,也是只作用于单个项目。

语法

1
2
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;

  • start:对齐单元格的起始边缘。
  • end:对齐单元格的结束边缘。
  • center:单元格内部居中。
  • stretch:拉伸,占满单元格的整个宽度(默认值)。

示例代码请看
justify-self 效果参考 张鑫旭大佬的博客
align-self 效果参考 张鑫旭大佬的博客

place-self

place-items可以让align-self和justify-self属性写在单个声明中。

1
place-self: <align-self> / <justify-self>;

总结

  • Grid布局则适用于更大规模的布局(二维布局),而Flexbox布局最适合应用程序的组件和小规模布局(一维布局)
  • 命名虽然支持中文,但由于CSS文件中文存在乱码的风险
  • 在Grid布局中,float,display:inline-block,display:table-cell,vertical-align以及column-*这些属性和声明对grid子项是没有任何作用的。这个可以说是Grid布局中的常识,面试经常会问的,一定要记得。
  • IE10-IE15虽然名义上支持Grid布局,但支持的是老版本语法(本文是介绍的全是2.0全新语法),
    兼容性查询请看can i use

参考

写给自己看的display: grid布局教程
CSS Grid 网格布局教程