# 宫格布局

TIP 参考链接: CSS Grid 网格布局教程 (opens new window)

# 概述

宫格布局和flex布局相似,但是宫格布局更复杂,能做出各种各样的布局,flex布局只能针对一个轴的方向进行布局,而宫格却可以进行二维布局,横向和纵向都可以。

宫格布局就像表格一样,有容器和子项目(单元格),里面的属性又可分为行和列、宽和高、单元格、网格线、间距,行列合并,排列方向、对齐方式、位置、布局,这些都有对应的css属性来进行控制和操作。

# 容器属性

# 1、display 属性

display属性定义宫格容器,可以是块元素,也可以定义为行内元素。

div {
  display: grid;
}

div {
  display: inline-grid;
}

注意,设为网格布局以后,容器子项目的float、display: inline-block、display: table-cell、vertical-align和column-*等设置都将失效。

# 2、行列设置

设置好容器后,我们需要使用 grid-template-columns、grid-template-rows 属性来定义子项目如何按照 nxm 宽高为多少进行排列。

grid-template-columns 定义每一列的宽,grid-template-rows定义每一行的高。

.container {
  display: grid;
  grid-template-columns: 200px 200px 200px;
  grid-template-rows: 100px 100px;
}

上面定义了一个宽为200,高为100的2x3的宫格布局,除了使用绝对单位,还可以使用百分比进行设置。 注意:这两个属性定义的是容器的布局方式,项目也只是指容器里的某块布局,和布局里具体的子元素自身不相关。

这两个属性还有一些其他简写的方法和补充属性

2.1 repeat()

如果定义多个行和列写起来很麻烦,我们可以使用repeat方法省略重复的值。

repeat接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值。 当然也可以重复某种模式。

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

.container {
  display: grid;
  grid-template-columns: repeat(2, 100px 200px 200px);
  grid-template-rows: repeat(2, 100px);
}

2.2 auto-fill关键字

auto-fill表示自动充满容器布局,如果容器大小不确定,项目大小确定,可以使用此属性来填充布局。

.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
}

2.3fr 关键字

为了方便表示比例关系,网格布局提供了fr关键字(fraction 的缩写,意为"片段")。如果两列的宽度分别为1fr和2fr,就表示后者是前者的两倍。

// 相同宽度的两列
.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

fr可以与绝对长度的单位结合使用。fr会占据容器剩余的空间进行等比例分配,并不会根据前面的具体数值进行分配。

.container {
  display: grid;
  grid-template-columns: 150px 1fr 2fr;
}

2.5minmax()

minmax(min, max) 表示长度可以在多少之间。

.container {
  display: grid;
  grid-template-columns: 150px minmax(100px, 200px);
}
// 如果设置fr则会根据容器宽度自动放大缩小
.container {
  display: grid;
  grid-template-columns: 150px minmax(100px, 1fr);
}

2.5 auto

auto表示占据父容器剩余空间

.container {
  display: grid;
  grid-template-columns: 150px auto 200px;
}

2.6 网格线名称

grid-template-columns属性和grid-template-rows属性里面,还可以使用方括号,指定每一根网格线的名字,方便以后的引用。

.container {
  display: grid;
  grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];
  grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];
}

# 3、间距设置

单元格之间的间距可以使用grid-row-gap、grid-column-gap 、grid-gap 这个几个属性来设置。

.container {
  display: grid;
  grid-template-columns: repeat(3, 200px);
  grid-template-rows: repeat(2, 100px);
  
  grid-row-gap: 20px; // 行间距
  grid-column-gap: 20px; // 列间距
  // 合并写法
  grid-gap: 20px 20px; // 行、列
}

# 4、行列合并

网格布局允许指定"区域"(area),一个区域由单个或多个单元格组成。grid-template-areas属性用于定义这些区域如何把单元格进行合并。

先看一个3x3布局如何用grid-template-areas表示,每个单元格都要有对应的名称来表示。a-i 9个区域表示1-9个单元格。

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  grid-template-areas: 'a b c'
                       'd e f'
                       'g h i';
}

把多个单元格合成一个区域,只要把名称取一样就表示把对应位置的单元格进行合并了。

.container {
  grid-template-areas: 'a a a'
                       'b b b'
                       'c c c';
}
// 即可以表示为上中下布局
.container {
  grid-template-areas: "header header header"
                       "main main main"
                       "footer footer footer";
}

如果某些区域不需要利用,则使用"点"(.)表示。

.container {
  grid-template-areas: "a a ."
                       "b b ."
                       "c c .";
}

# 5、项目排列方向

像flex布局一样,可以定义轴的方向,宫格布局也可以使用grid-auto-flow属性定义项目的排列方向。默认项目的排列顺序是"先行后列",即先填满第一行,再开始放入第二行。

.container {
  grid-auto-flow: row | row-reverse | column | column-reverse;
}

它可能有4个值。

row(默认值):先行后列。
column:先列后行。
row dense:表示"先行后列",并且尽可能紧密填满,尽量不出现空格。
column dense: 表示"先列后行",并且尽量填满空格。

row dense 和 column dense 表示排序方向按照主方向排列后,如果多出剩余的空白区域该如何让其他项目填充。

比如一个宽500的容器,前两个单元格是200,第三个是100,那么正常情况下,第一个后面会空出100的空白区域,第三个会排在第二行第二个单元格后面。

如果使用row dense那么第三个就会填充到第一行的空白区域,后面的依次填充。

# 6、项目对齐方式

我们可以通过justify-content 、align-content、place-content 属性对容器内的所有单元格设置整体对齐方式。

.container {
  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: 项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔。

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

.container {
  place-content: space-around space-evenly;
}

# 7、项目内的对齐方式

上面是设置容器内单元格的对齐方式,这个是设置单元格内元素的对齐方式,当然单元格内真正的元素可以设置其内元素的对齐方式。

.container {
  justify-items: start | end | center | stretch;
  align-items: start | end | center | stretch;
}

这两个属性的值都一样,一个设置水平方向,一个设置垂直方向。

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

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

.container {
  place-items: center center;
}

# 8、多余项目的行列设置

如果设置的单元格超出了我们自定义的行列数,或者设置某个单元格在自定义的网格外面,浏览器会自动生成多余的网格来放置,默认的这些多余的单元格浏览器会自动内容大小设置宽高,我们也可以通过grid-auto-columns和grid-auto-rows 来指定这些多余单元格的大小,写法和行列设置一样。

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  grid-auto-columns: 80px;
  grid-auto-rows: 50px;
}

# 9、属性简写

grid-template属性是grid-template-columns、grid-template-rows和grid-template-areas这三个属性的合并简写形式。

grid属性是grid-template-rows、grid-template-columns、grid-template-areas、 grid-auto-rows、grid-auto-columns、grid-auto-flow这六个属性的合并简写形式。

从易读易写角度考虑,不建议简写。

# 项目属性

上面都是针对容器里的属性进行设置,项目也可以指定自身的位置、对齐方向等。

# 1、指定项目的位置

指定项目的位置具体方法就是指定项目的四个边框,分别定位在哪根网格线,指定到哪就占据到哪个单元格。并不是像flex通过数字来定位。

grid-column-start:左边框所在的垂直网格线
grid-column-end:右边框所在的垂直网格线
grid-row-start:上边框所在的水平网格线
grid-row-end:下边框所在的水平网格线

比如指定1号项目的左边框是第二根垂直网格线,右边框是第四根垂直网格线。则1号项目就会占据2、3两个单元格。

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
}
.item-1 {
  grid-column-start: 2;
  grid-column-end: 4;
}

这个指定边距和行合并列合并很像,还可以通过span来直接指定 跨越 多少个单元格。

.item-1 {
  grid-column-start: span 2; // 直接占据1、2两个单元格
}

grid-column属性是grid-column-start和grid-column-end的合并简写形式。

grid-row属性是grid-row-start属性和grid-row-end的合并简写形式。

.item {
  grid-column: <start-line> / <end-line>;
  grid-row: <start-line> / <end-line>;
}
// 可以和span综合一起用。
.item-1 {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}
/* 等同于 */
.item-1 {
  grid-column: 1 / span 2;
  grid-row: 1 / span 2;
}

# 2、指定项目的区域

和指定位置一样,项目也可以单独指定自己所在的区域。grid-area属性指定项目放在哪一个区域。

.container{
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  grid-template-areas: 'a b c'
                       'd e f'
                       'g h i';
}
.item-1 {
  grid-area: e;
}

grid-area属性还可用作grid-row-start、grid-column-start、grid-row-end、grid-column-end的合并简写形式,直接指定项目的位置。

.item {
  grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
}

.item-1 {
  grid-area: 1 / 1 / 3 / 3;
}

# 2、项目的对齐方式

我们可以通过justify-self、align-self 属性设置单元格内容的对齐方式。它和 justify-items、align-items用法一模一样。

.container {
  justify-self: start | end | center | stretch;
  align-self: start | end | center | stretch;
}

两个属性取值一样

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

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

.container {
  place-self: center center;
}