最近在参加一个小程序比赛,其中在做瀑布流布局的时候,有人拿Grid网格布局来做的,但是我觉得瀑布流并不是个用Grid网格布局来做,因为它每一个项目占多少网格,都需要人工去指定。虽然我觉得Grid网格布局不是个做瀑布流, 但是我觉得它还是非常强大的,甚至觉得比Flex强大。那么这篇文章就是来记录Grid网格布局的一个使用教程的。当翻阅可看。
前言
在我们web页面开发过程中,我们可以使用css控制页面中元素的位置,主要的布局样式有以下几种:
- 正常的布局流
- display 属性
- 弹性盒子(FlexBox)
- 网格(display:table)
- 浮动(float)
- 定位(position)
- CSS Grid网格布局
- 多列布局(Multi-column layout)
什么是网格布局(Grid)?
网格布局(Grid)将网页分成一个个网格,可以任意组合不同的网格,设计出各种各样的的布局。
网格布局(Grid)将容器划分成“行” 和 “列”, 然后指定“项目所在”的单元格,可以看做是二维布局。Grid 布局远比 Flex 布局强大。
基本概念
学习 Grid 布局之前,需要了解一些基本概念。
容器和项目
使用网格布局的区域,称为“容器”(container),容器内采用网格定位的子元素,称为“项目”(item)
例如:
| 1 | <div class="container"> | 
如果我们给 class 为 container的元素设置它为 网格布局(Grid)。那么该元素就是容器, 里面的三个class为tem的元素就是项目。
注意:项目只能是容器最顶层子元素,不包含项目的子元素。例如上面的span标签就不是项目。Grid布局就对项目生效。
行,列,单元格,网格线
 
行和列:
容器里面的水平区域称为”行“(row);垂直区域称为”列“(column)。 上图中的水平绿色区域就是”行“。垂直的蓝色区域就是”列“。
单元格:
行和列的交叉区域称为”单元格“(cell)。如上图显示”单元格“的区域就是其中的一个单元格
网格线:
划分为网格的线,称为:”网格线“(grid line)。水平网格线划分出行,垂直网格线划分出列。日上图中就有5个水平网格线 和 10 个垂直网格线。
容器属性
Grid 布局的属性分为两类。一类是定义在容器上面,称为容器属性;另一类定义在项目上面,称为项目属性。这里我们先讲容器属性。
display 属性
使用display:grid指定一个容器采用网格布局。
| 1 | .grid { | 
如:
默认情况下,容器元素都是块级元素,单也可以设置为行内元素。| 1 | .grid { | 
如:
上面的这个例子指定了 class 为 grid的 div 为行内元素,该元素内部的项目使用网格布局。
注意: 设置网格布局之后,容器项目的 float,display: inline-block,display: table-cell、vertical-align和column-*等设置将会失效。
grid-template-columns属性
grid-template-rows 属性
容器指定了网格布局之后,就需要划分行和列。grid-template-columns 属性用来定义每一列的宽度,grid-template-rows属性用来定义每一行的行高。
例如我们上面两个例子:
| 1 | .grid { | 
如上:指定了一个两行两列的网格,列宽和行高都是 100px。
当然grid-template-columns 和grid-template-rows属性除了可以使用绝对值外,也可以使用百分比的
| 1 | .grid { | 
repeat()
有时候列宽可能是固定, 到那时我们在指定每一列的列宽时,都需要一一写上。就很麻烦。这时候就可以使用repeat()函数,简化重复的值。
repeat():接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值。例如上面的代码就可以写成:
| 1 | .grid { | 
repeat(): 也可以重复某种模式。如:
| 1 | .grid { | 
如上这个例子的代码就表示:第一列和第三列的宽为80px,第二列和第四列的宽为100ox。
auto-fill 关键字
有时候单元格的大小是固定的,但是容器的大小是不固定的。如果我们是希望没一行或者每一列能容纳尽可能多的单元格。就可以使用auto-fill关键字了。这个关键字表示自动填充。
| 1 | .grid { | 
例子代码表示:每列列宽为100px,然后自动填充,直到容器不能放置更多的列。
fr关键字
为了方便的表示比列关系,网格布局提供了fr 关键字。如果两列的了宽度分别是 1fr 和 2fr 表示 后者的列宽是前者的两倍。
如:
| 1 | .grid { | 
这表示容器的高度被分为2等份,第一行和第二行的行高都各占了一份。容器的宽被分成2等份,第一列和第二列的列宽都个占了1份。
再如:
| 1 | .grid { | 
表示容器的宽被分成了5份等份,第一列的列宽占了2份。第二列的列宽占了一份,第三列的列宽占了3份。
minmax()
minmax()函数产生一个长度范围。它有两个参数,最大值和最小值。
| 1 | .grid { | 
这就表示,该项目的宽度不小于100px,不大于200px
auto关键字
该关键字表示项目的宽度有浏览器自己决定。
| 1 | .grid { | 
表示第一个项目的宽度基本是等于该单元格的最大宽度。
网格线的名称
使用grid-template-columns属性和 grid-template-rows属性时,可以使用方括号,指定每一根网线的名字。方便之后的引用。
| 1 | .grid { | 
如上的代码指定的网格布局为两列两行,因此有3根水平网格线和3根垂直网格线。方括号里面依次是这6根网格线的名字。
注意:网格布局允许同一根线可以有多个名字。如:
| 1 | grid-template-columns: [a1 m1] auto [a2] 100px [a3]; | 
grid-row-gap 属性,
grid-column-gap属性
grid-gap 属性
grid-row-gap属性设置行与行之间的间隔行间距
grid-column-gap 属性设置列与列之间的间隔(列间距)
| 1 | .grid { | 
grid-gap 属性是 grid-column-gap和 grid-row-gap的合并简写。语法:grid-gap: <grid-row-gap> <grid-column-gap>
注意:如果grid-gap省略了第二个值。那么浏览器会默认为第二个值等于第一个值
注意:根据最新的标准。grid-row-gap,grid-column-gap,grid-gap 这三个属性不用写前缀grid。
grid-template-areas 属性
网格布局允许执行“区域”(areas),一个区域有多个单元格组成。那么grid-template-areas属性就是用来定义区域的.
| 1 | .grid { | 
上面的这个例子我们审查元素来看看。可以看出区域被分成了4部分 a b c d;
 
多个单元格合并成一个单元格的写法:
| 1 | grid-template-areas: 'a a' | 
如图:
 
这样就把把四个单元格分成了 a b 两个区域。
如果某个区域不需要的话,则使用 . 来表示。
| 1 | grid-template-areas: 'a .' | 
如图:
 
注意:区域的命名会影响到网格线,每个区域的起始网格线会自动命名为区域名-start,终止网格线会自动命名为区域名-end.
grid-auto-flow 属性
grid-auto-flow属性用来设置容器项目的放置顺序。主要有四个值:
row:
默认值。表示放置顺序为”先行后列“。 也就是先填满第一行。再放入第二行。
我们上面的所有的例子都是这样的(看元素中的数字可以看出),都是先放满第一行,再放如第二行。
column:
表示”先列后行”。
如:
从例子中可以看出来 1,2 在左边;3, 4 在右边。这是因为我们设置:
| 1 | /* 先列后行 */ | 
row dense:
表示”先行后列”,每一行尽可能精密填满,尽量不要有空格;
这个设置的意义在哪里呢? 我们先来看一个例子:
在这个例子中, 我们采用的是”先行后列“的放置顺序;设置第一个项目和第二个项目列宽占两个单元格:| 1 | grid-column-start: 1; | 
然后就得到如上的结果,从结果可以看出,第一行空出了一个空白的地方。这是为什么呢? 这是因为第三个项目默认跟着第二个项目,所以会排在第二个项目之后。
 但是我们把放置顺序改为:row dense。那么结果就是:
这个例子就可以看出来: 先是填满第一行,再填满第二行,并且每一行尽量不要有空格。所以第三个元素会在第一个元素后面
column dense
表示 ”先列后行“ 并且每一列尽量不要有空格。
跟上一个的适用场景一样。 我们将放置顺序改为column dense;那么将得到这样的结果:
justify-items 属性
align-items 属性
place-items 属性
justify-items属性用来设置单元格内容的水平位置。align-items 属性用来设置单元格内容的垂直位置。这两个都有如下的值:
- start:对齐单元格的起始位置
- end:对齐单元格的结束边缘
- center:单元格内部居中
- stretch:项目大小没有指定时,拉伸占据整个网格容器。
这里需要注意的是单元格内容
例:
如上的代码, 我们让每个单元格里面的内容水平位置居中,垂直位置居中。我们可以通过审查元素来看:
 
可以看出来,class为 item的元素在第一个单元格的位置都是单元格内部居中(水平位置居中,垂直位置居中)。
其他值我就不一一举例了。可以直接使用上面的例子,修改  justify-items 和 align-items的值看效果。
place-items 属性是 align-items属性和justify-items属性的合并简写形式。
| 1 | place-items: <align-items> <justify-items>; | 
例:
如上的例子: 我们使用`place-items`设置了 垂直方向是对齐单元格的结束方向。水平方向是居中。我们可以审查元素来看: 
可以看出 来class为 item的元素在第一个单元格的位置是垂直方向是对齐单元格的结束方向。水平方向是居中。
注意: place-items属性的第二个参数如果省略的话,则浏览器默认与第一个值相等。
justify-content 属性
align-content 属性
palce-content 属性
justify-content 属性是设置整个内容区域在容器里面的水平位置,align-content属性是设置整个内容区域在容器里面的垂直位置。这两个属性都有如下的值:
- start: 对齐容器的起始边框;  
- end:对齐容器的结束边框;  
- center:容器内部居中;  
- stretch - 项目大小没有指定时,拉伸占据整个网格容器。  
- space-around - 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍。  
- space-between - 项目与项目的间隔相等,项目与容器边框之间没有间隔。  
- space-evenly - 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔。  
place-content属性是 justify-content属性和align-content属性的合并缩写形式:
| 1 | place-content: <align-content> <justify-content> | 
如果place-content省略第二个值,那么浏览器就会默认第二个值等于第一个值。
grid-auto-columns 属性
grid-auto-rows 属性
有时候我们的项目的指定在网格的外面,那么浏览器就会自动根据单元格的大小生成多余的网格。
grid-auto-cloumns属性 和 grid-auto-rows属性就是用来设置当浏览器自动创就按多余的网格的列宽和行高。这两个属性的法与grid-template-columns,grid-template-rows是一样的;
如:
这个例子:第7 个项目超出了当前的网格(使用了grid-row-start 和 grid-column-start下面会有介绍),那么浏览器会自动生成多余的网格,我们设置多余的网格列宽和行高都是50px;
项目的属性
定义在项目上的属性。
grid-column-start 属性
grid-column-end 属性
grid-row-start 属性
grid-row-end 属性
容器中的项目是可以指定的。使用这四个属性定义项目的边框。这四个属性是定义项目在哪根网格线;
- grid-column-start 属性:项目左边框所在的垂直网格线;
- grid-column-end属性:项目右边框所在的垂直网格线;
- grid-row-start 属性:项目上边框所在的水平网格线;
- grid-row-end 属性:项目下边框所在的水平线网格线;
我们讲解上个属性的时候也用到了这些属性 grid-row-start 和 grid-column-start。我们可以再举个例子:
我们可以通过审查元素看出来第7个元素占的网格线情况:
 
第七个项目的上边框在水平网格线的第四根,左边框在垂直网格线的第一根。下边框和右边框没有指定,所以会采用默认位置(下边框滴5根网格线。有边框第二根网格线)。
再看一个例子:
我们可以通过审查元素看出来第7个元素占的网格线情况:
 
我们可以看出第一个项目的左边框在垂直网格线的第二个,右边框在垂直网格线的第四个网格线。上下边框没有指定使用默认位置。除了第一个项目之外,其他项目没有指定位置,由浏览器自动布局。这时它们的位置由容器的grid-auto-flow属性决定,这个属性的默认值是row,因此会”先行后列”进行排列
注意1:这四个属性的值,也可以指定为网格线的名字。
第一个项目的左边框指定为a2的网格线,右边框指定为a4的网格线,
注意2:这四个属性可以使用 span关键字。表示上下边框(左右边框)之间跨越多少网格。
第一个项目的左右边框,上下边框都跨越2个网格(绿色部分)。
