# Grid 布局教程

CSS Grid 布局系统是一个比较新的布局方式,它借鉴了表格布局的思想,将网页划分为不同的网格,实现网页的二维布局效果。它和 Flex 布局有点像,但较为明显的区别是,Flex 布局往往应用于一维层次的布局(轴线布局),没有 Grid 那么强的灵活性。

这样的特性决定了 Grid 布局往往被应用于网页的大框架的划分而 Flex 布局更适合应用于小部件的排列,两者并不会有太大的地位冲突,应该结合起来使用。

Grid 布局更加贴近设计稿中的布局规划,它的出现得以使前端从各式各样的 hack 与 trick 中解放出来,使代码更加明确而简洁。

越来越多的页面将会使用 Grid 布局,哪怕旧浏览器上不的支持度较低,它也会随着时间逐渐发展成为 CSS 布局主流。


# 属性速览


# 基本概念

与 Flex 布局类似的,Grid 布局也有“容器”(container)和“项目”(item)的概念,以便于我们称呼被排版的元素们。

使用display: grid;语句,可以为指定容器应用 Grid 布局。

同样的,grid 默认为块级元素。指定为inline-grid属性,容器自身会表现为内联元素(并不影响项目的布局)。

外层的容器相当于框架,可以使用网格线(grid line)将其划分出多个(row)与(column),被划分出来的网格被称为单元格(cell)。

项目可以放在一个单元格里,也可以占有多个单元格。


# 容器属性

# grid-template-rows

# grid-template-columns

这两个属性分别用于定义:每一行的高度、每一列的宽度。

# px 单位

.container {
  display: grid;    /* 以下代码示例省略该行 */
  grid-template-rows: 120px 60px;
  grid-template-columns: 60px 60px 60px;
}

以上代码创建了一个两行三列的网格。

-------------
|   |   |   |
|   |   |   |
-------------
|   |   |   |
-------------

# % 单位

如果容器定义了 width 与 height,可以使用百分比作为行与列的宽度。

.container {
  width: 192px;
  height: 192px;
  grid-template-rows: 66.7% 33.3%;
  grid-template-columns: 33.3% 33.3% 33.3%;
}

# auto 关键字

在设置长度时使用auto关键字,代表让浏览器决定该值,它会尽可能地取得不小于min-width的最大值。

.container {
  grid-template-columns: 60px auto 60px;
}

# fr

fr关键字意为“片段”(fraction),是一种相对单位,比如2fr1fr的两倍。

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

也可以和绝对单位进行混用,实现更多的布局效果。


# repeat()

使用repeat()函数,可以简化重复值。

.container {
  grid-template-rows: 66.7% 33.3%;
  grid-template-columns: repeat(3, 33.33%);
}

# auto-fill 关键字

当单元格大小确定而容器大小不确定时,可以在repeat()中使用auto-fill关键字,使自动填充尽可能多的单元格。

.container {
  grid-template-rows: 66.7% 33.3%;
  grid-template-columns: repeat(auto-fill, 60px);
}

# minmax()

生成一个区间,将长度限制在这个范围中。

.container {
  grid-template-columns: 1fr 1fr minmax(30px, 1fr);
}

# 为网格线取名

如果后面需要以网格线为准进行引用,可以在grid-template-rowsgrid-template-columns属性内使用方括号为网格线命名。

.container {
  grid-template-rows: [r1] 120px [r2] auto [r3];
  grid-template-columns: [c1] 60px [c2] 60px [c3] auto [c4];
}
    c1  c2  c3  c4
r1  -------------
    |   |   |   |
    |   |   |   |
r2  -------------
    |   |   |   |
r3  -------------

# grid-template-areas

和定义网格线类似的,Grid 布局支持定义单元格组成的区域,属于同一区域的单元格设置相同的名字。

.container {
  grid-template-columns: 60px 60px 60px;
  grid-template-rows: 60px 60px 60px;
  grid-template-areas: 'a a b'
                       'a a b'
                       'c d e';
}

则有类似下面的布局:

-------------
|   a   | b |
|       |   |
-------------
| c | d | e |
-------------

如果有某区域不需要,则用点(.)表示。

⚠ 注意:区域的命名会影响到网格线的名称。每个区域的起始网格线,会自动命名为区域名-start,终止网格线自动命名为区域名-end



# grid-row-gap

# grid-column-gap

grid-row-gap属性设置行与行的间隔(行间距),grid-column-gap属性设置列与列的间隔(列间距)。

.container {
  grid-row-gap: 16px;
  grid-column-gap: 8px;
}

# grid-gap

grid-gap属性为grid-column-gapgrid-row-gap的合并简写形式,其语法如下:

grid-gap: <grid-row-gap>[ <grid-column-gap>];

省略第二个值时,默认都等于第一个值。(后面出现的双值可省略一值的情况都是这种处理方式)

最新标准中,gap相关属性去掉了grid-前缀,可以使用row-gap代替grid-row-gap。为了兼容性,仍然支持使用grid-前缀作为属性名。



# grid-auto-flow

类似于 Flex 布局里的flex-flow,设置项目在网格中的放置顺序与方式。

grid-auto-flow: (row | column) [dense];

默认值为row,即横向优先顺序填充。设置为column,则变成竖向优先顺序填充。

但如果排在前面的项目较大而后面的项目较小,可能会出现以下情况:

如果加上dense,则会采用尽量填满所有空单元格的方案。



# grid-auto-rows

# grid-auto-columns

虽然使用 Grid 布局时,我们会规定好行列数,但如果想要添加更多行或列,或添加元素到超出规定的行列区域之外的区域时,Grid 会自动为我们生成新的行与列,而行高与列宽则通过grid-auto-rowsgrid-auto-columns进行设置。

例子 (opens new window)

.container {
  grid-template-columns: 60px 60px 60px;
  grid-template-rows: 60px 60px 60px;
  grid-auto-rows: 30px; 
}

令8和9元素插入到网格之外,得到效果如下:



# justify-items

# align-items

设置项目在容器区域内水平对齐垂直对齐的方式,可以取四个值:

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

举个左对齐的例子:

.container {
  justify-items: start;
}

# place-items

place-itemsjustify-itemsalign-items属性的合并简写属性。

place-items: <align-items>[ <justify-items>];

# justify-content

# align-content

justify-content属性设置按列分隔的内容区域在容器内的水平(左中右)排列分布方式。

align-content属性设置按行分隔的内容区域在容器内的垂直(上中下)排列分布方式。

两种属性都可取名字相同的七种值(下以justify-content为例):

分布方式
start(默认值) 靠左对齐
end 靠右对齐
center 居中
stretch 拉伸占据整个网格容器
space-between 两端对齐,项目之间间隔相等
space-around 每个项目两侧的间隔相等
space-evenly 项目与项目、项目与容器边框之间间隔相等

每个值的效果如下:

start

end

center

stretch

space-between

space-around

space-evenly

# place-content

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

place-content: <align-content>[ <justify-content>];


⚠注意:以下合并简写属性合并过多的属性值,故不推荐使用,以提高可读性,便于记忆。

# grid-template

grid-template属性是:

  • grid-template-columns
  • grid-template-rows
  • grid-template-areas

这三个属性的合并简写形式。


# grid

grid属性是:

  • grid-template-rows
  • grid-template-columns
  • grid-template-areas
  • grid-auto-rows
  • grid-auto-columns
  • grid-auto-flow

这六个属性的合并简写形式。



# 项目属性

# grid-column-start

# grid-column-end

# grid-row-start

# grid-row-end

这四个属性用于指定项目的边框应该定位到哪一条网格线上。

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

例子 (opens new window)

.item-1 {
  grid-column-start: 2;
  grid-column-end: 4;
}

# grid-rowgrid-column的不同之处

虽然由于没有设置grid-auto-flow: dense;,所以2排在1的后面,但如果对项目1指定了grid-row的话,则会使得项目1表现得类似float之于内联元素那样,离开了“网格流”,使得后面的元素会尝试填充项目1前面的单元格的空间。

例子1 (opens new window)

.item-1 {
  grid-column-start: 2;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
}

例子2 (opens new window)

.item-5 {
  grid-column-start: 1;
}

形象地说:

  • 例子1中,grid-row可以顶掉他想定位到的网格的其他内容,而其他内容会绕着他像水流一样接着排列;
  • 例子2中,如果只单独设置了grid-column,则会考虑先后顺序问题,不会超前于前面的元素,也不会让后面的元素排到自己的前面。

# 网格线名

另外,前面如果有给网格线取名,则可以使用网格线的名字来指定。

.item-1 {
  grid-column-start: header-start;
  grid-column-end: header-end;
}

# span 关键字

span表示“跨越",即左右边框(上下边框)之间跨越多少个网格。

.item-1 {
  grid-column-end: span 2;
}

当没有指定其他时,等价于下面的写法:

.item-1 {
  grid-column-start: span 2;
}

这两种写法都会让项目1占据单元格1和单元格2,它们的基准都是从start网格边往end方向跨越两格。

而下面这种写法比较容易看出区别:

/* 以start边为基准跨越两格,占据单元格1、2 */
.item-1 {
  grid-column-start: 1;
  grid-column-end: span 2;
}

/* 以end边为基准反向跨越两格,占据单元格2、3 */
.item-1 {
  grid-column-start: span 2;
  grid-column-end: 4;
}

# grid-column

# grid-row

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

语法:

grid-row: <row-start> / <row-end>;
grid-column: <column-start> / <column-end>;

其中第二个值是可选的,默认只跨越一个单元格。


例子:

.item-1 {
  grid-column: 1 / 3;
  grid-row: 1 / 2;
}
/* 等同于 */
.item-1 {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
}

# grid-area

grid-area属性指定项目放在哪一个区域。

.item-1 {
  grid-area: header;
}

也可以当作grid-row-startgrid-column-startgrid-row-endgrid-column-end的合并简写属性:

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

省略参数的表现形式类似于边距的值复制,只不过参数顺序为顺时针。



# justify-self

# align-self

为某一个项目单独设置水平/垂直对齐方式,即justify-items/align-items的单独版。

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

# place-self

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

place-self: <align-self>[ <justify-self>];


# 本文参考

CSS Grid 网格布局教程 - 阮一峰 http://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html (opens new window)


上次更新: 2020/1/9 01:00:39