# Grid 布局教程
CSS Grid 布局系统是一个比较新的布局方式,它借鉴了表格布局的思想,将网页划分为不同的网格,实现网页的二维布局效果。它和 Flex 布局有点像,但较为明显的区别是,Flex 布局往往应用于一维层次的布局(轴线布局),没有 Grid 那么强的灵活性。
这样的特性决定了 Grid 布局往往被应用于网页的大框架的划分而 Flex 布局更适合应用于小部件的排列,两者并不会有太大的地位冲突,应该结合起来使用。
Grid 布局更加贴近设计稿中的布局规划,它的出现得以使前端从各式各样的 hack 与 trick 中解放出来,使代码更加明确而简洁。
越来越多的页面将会使用 Grid 布局,哪怕旧浏览器上不的支持度较低,它也会随着时间逐渐发展成为 CSS 布局主流。
# 属性速览
容器
- grid 网格
- grid-template 定义网格、区域
- grid-template-rows 网格行高
- grid-template-columns 网格列宽
- grid-template-areas 区域
- grid-gap 单元格间距
- grid-row-gap 行间距
- grid-column-gap 列间距
- grid-auto-rows 默认行高
- grid-auto-columns 默认列宽
- grid-auto-flow 流动方式
- grid-template 定义网格、区域
- place-items 对齐方式
- justify-items 水平对齐
- align-items 垂直对齐
- place-content 分布方式
- justify-content 水平分布
- align-content 垂直分布
- grid 网格
项目
- grid-area 所在网格区域
- grid-column 列定位
- grid-column-start 列起始网格线
- grid-column-end 列结束网格线
- grid-row 行定位
- grid-row-start 行起始网格线
- grid-row-end 行结束网格线
- grid-column 列定位
- place-self 单独设置对齐方式
- justify-self 单独设置水平对齐方式
- align-self 单独设置垂直对齐方式
- grid-area 所在网格区域
其他
- fr 相对单位
- repeat() 简写重复参数
- auto-fill 关键字 自动扩充单元格
- minmax() 区间限制
- span 关键字 跨越单元格
# 基本概念
与 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),是一种相对单位,比如2fr
是1fr
的两倍。
.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-rows
和grid-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-gap
和grid-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-rows
和grid-auto-columns
进行设置。
.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-items
即justify-items
和align-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 | 项目与项目、项目与容器边框之间间隔相等 |
每个值的效果如下:
# 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 | 下边框所在的水平网格线 |
.item-1 {
grid-column-start: 2;
grid-column-end: 4;
}
# grid-row
与grid-column
的不同之处
虽然由于没有设置grid-auto-flow: dense;
,所以2排在1的后面,但如果对项目1指定了grid-row
的话,则会使得项目1表现得类似float
之于内联元素那样,离开了“网格流”,使得后面的元素会尝试填充项目1前面的单元格的空间。
.item-1 {
grid-column-start: 2;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 3;
}
.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-start
和grid-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-start
、grid-column-start
、grid-row-end
、grid-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)
← Flex 布局教程 CSS 居中专项讲解 →