Grid在MDN上翻译为网格布局,在《CSS权威指南》中翻译为栅格布局,其实是同一种布局方案,本文语句主要整理自《CSS权威指南》一书
1. 栅格布局
Grid 是一种强大的布局方案,也是最为普适的布局方案,允许在Web上创建二维布局,通过对父元素定义不同参数的行与列垂直线,再将子元素部署于行列网格上,由此实现各类灵活的布局,如:
通过标准流、float、flex也可以实现类似的布局,但这些方案往往需要更多的DOM元素,或者需要指定更多的参数,并且很多情况下无法做到自适应,此时,grid布局方案的优势就体现出来了。并且语法兼容性也很好,除了那位大爷…..
Chrome | Edeg | Firefox | IE | Opera | Safari |
57 | 16 | 52 | 不支持 | 44 | 10.1 |
2. 栅格容器
创建栅格的第一步就是创建一个栅格容器,并将其中的内容定义为栅格布局
2.1 栅格属性
display: grid/inline-grid;
指定容器布局方式为栅格布局,该属性和 block 与 inline-block 值相似
2.2 定义栅格模板
grid-template-columns: 值;
grid-template-rows: 值;
将容器划分为行列栅格,栅格线的值可以为固定值、百分比、fr关键字、repeat()语句、minmax()语句、calc()函数等,并且参数可以混用
2.2.1 固定值行列轨道宽度
将子元素宽高设为固定值,单位可以为px,也可以为em、rem等相对单位
如:给父元素指定行列轨道宽度,子元素可以不设置任何参数
div{
display:grid;
grid-template-columns:50px 60px 100px;
grid-template-rows:50px 60px 100px;
}
box1
box2
box3
box4
box5
box6
box7
box8
box9
类似的取值可以为
grid-template-columns:5em 5em 5em;
2.2.2 百分比配置宽高
将元素的宽高按百分比配置,可以让网页元素自适应不同屏幕大小
如:元素宽高分别为20% 20% 50%
div{
display:grid;
grid-template-columns:20% 20% 50%;
grid-template-rows:20% 20% 50%;
border:1px solid black;
box-sizing: border-box;
}
box1
box2
box3
box4
box5
box6
box7
box8
box9
百分比是基于父容器的宽度和高度计算,不管子元素内容大小如何变化也不会变,因此要给与父元素宽高参数,即不能再使用子元素撑开父元素了。若子元素宽高相加不到100%,则剩余部分空置
2.2.3 fr按比例配置宽高
grid布局提供了 fr 关键字(fraction)用于表示比例关系
如:元素宽高比为1:2:2
div{
display:grid;
grid-template-columns:1fr 2fr 2fr;
grid-template-rows:1fr 2fr 2fr;
border:1px solid black;
box-sizing: border-box;
}
box1
box2
box3
box4
box5
box6
box7
box8
box9
配合其他值来实现弹性布局
grid-template-columns:150px 1fr 10%;
第一列宽为150px,最后一列宽为10%,剩下宽度给中间一列
2.2.4 定义栅格线名称
可以使用[ ]为边框线起名字,并且同一条线的名称可以有无数多个,如:[a1 b1]为同一条线取名a1和b1
如:元素宽高比为1:2:2
div{
display:grid;
grid-template-columns: [c1] 80px [c2] 80px [c3] 80px [c4];
grid-template-rows: [r1] 60px [r2] 60px [r3] 60px [r4];
border:1px solid black;
box-sizing: border-box;
}
box1、box4、box7左边框线相连为c1,右边框线相连为c2;
box1、box2、box3上边框线相连为r1,下边框线相连为r2
其他以此类推
box1
box2
box3
box4
box5
box6
box7
box8
box9
2.2.5 repeat()重复填充
对于多个宽高值相同的元素,可以使用repeat()语句简写
如:
1. 对于grid-template-columns: 5em 5em 5em;
该语句可以简写为
grid-template-columns: repeat(3,5em);
2. 类似地可以创建宽度有一定规律的子元素
如:创建宽度依次为20px,40px,60px,20px,40px,60px的6列元素
grid-template-columns: repeat(2, 20px 40px 60px);
3. 还可以repeat()前后添加不想重复的宽高值
grid-template-columns: repeat(2,1em 5em) 2em;
这就生成了1em 5em 1em 5em 2em的网格
4. 百分号和比例依旧适用
grid-template-columns: repeat(3,33.3%);
5. 如果包含了栅格线名,名称也会被复制
grid-template-columns: repeat(3,[top] 5em [bottom]);
则会生成
[top] 5em [bottom top] 5em [bottom top] 5em [bottom]
即:中间的栅格线将会有两个名称,该语句等同于:
grid-template-columns: [top] 5em [bottom top] 5em [bottom top] 5em [bottom];
2.2.6 minmax()限制尺寸
当子元素溢出父容器之外时,除了使用overflow: hidden;外,还可以使用minmax(最小值,最大值)来限制宽高尺寸
如:将剩余空间分配给第二列,但又要避免他被挤占得太小
grid-template-columns:5em minmax(10%,1fr) 2em;
注意!当minmax()中最大值小于最小值时,最大值将失效。如minmax(100px,2em)中,当2em计算值小于100px时,元素宽高将被解析为100px
2.2.7 calc()计算尺寸
grid是支持calc()语句的,只是有时候不太适用
如:第二列宽度通过计算得出
grid-template-columns:2em calc(100%-1.5em) 10%;
2.2.8 根据内容自适应
子元素宽高还可以根据子元素内容,通过max-content、min-content、fit-content来实现栅格自适应
- max-content:解析为尽可能大的空间,以防换行
- min-content:解析为尽可能小的空间,能够显示内容即可
- fit-content:解析为空间尽可能小,但如果超过指定空间大小就换行
如:尽可能容纳内容
div{
display:grid;
grid-template-columns:max-content max-content max-content;
grid-template-rows:max-content max-content max-content;
}
可以看到,每一列的宽度由该列有最长内容的列宽决定,行类似。当父元素指定宽度时,这可能会溢出到父容器之外
1
22
33333333
44444444444
5
6
77
8888
9
配合minmax()使用可以不破坏外部布局,但会挤压内部空间
div{
display:grid;
grid-template-columns:minmax(0,max-content) minmax(0,max-content) minmax(0,max-content);
grid-template-rows:max-content max-content max-content;
}
1
22
33333333
44444444444
5
6
77
8888
9
fit-content用于限制最大长度,类似于max-width
指定三列宽均为50等宽字符,当未满50ch时按实际字符长度算,超过该值则进行换行,即最大值只能为50ch
div{
display:grid;
grid-template-columns:fit-content(50ch) fit-content(50ch) fit-content(5.0ch);
}
只指定宽度,高度自适应,第一第二列未满50ch时,以各自长度为列宽,第三列超过50ch,则进行换行,以50ch为列宽
the night
Avicii
He said one day you will leave this world behind So live a life you will remember
当父容器较小时,第一、第二列即便未满50ch也可能会进行换行,以保证不会溢出父亲容器
2.2.9 auto-fill自动填充
当父容器宽度固定,可以使用auto-fill让子元素根据大小自动填充
如:
div{
display:grid;
width:50vh;
grid-template-columns:repeat(auto-fill,5em);
grid-template-rows:max-content max-content max-content;
}
在父容器中尽量排列宽3em的元素,排列到第一行排完,如果剩下空间不足3em,则剩余子元素将进行换行
box1
box2
box3
box4
box5
box6
box7
box8
box9
1. 一个父容器的宽/高只能有一次自动排列,因此下述语句是不允许的
grid-template-columns: repeat(auto-fill,5em) repeat(auto-fill,2em);
2. 但可以固定尺寸的repeat与自动填充的repear共存,如:
grid-template-columns: repeat(2,5em) repeat(auto-fill,2em);
或者
grid-template-columns: repeat(auto-fill,5em) repeat(3,2em);
但无论语序如何,grid总会为固定尺寸的元素分配空间,因此auto-fill会被最后才被分配空间
2.3栅格间距
通过row-gap、column-gap来设置栅格见的行、列间隔。或者将两个属性合并为一个 grid-gap:行间隔 列间隔;
给父容器添加该属性
div{
display:grid;
width:50vh;
height:50vh;
grid-template-columns:repeat(3,60px);grid-template-rows:repeat(3,60px);
row-gap:10px;
column-gap:10px;
}
如图所见,添加间隔可能导致栅格溢出,这两个属性可合并为 grid-gap ,如果该语句之后的值只有一个,则解析为行列间隔都为该值。
grid-gap:10px 10px;
等价于
grid-gap:10px;
box1
box2
box3
box4
box5
box6
box7
box8
box9
3. 栅格区域
此前都是给父容器添加属性,但如果同时给子元素添加相应属性可以做出更好的布局
3.1 调用栅格线名
通过grid-template-columns、grid-template-rows定义栅格宽高和栅格线名后,可以通过下列语句调用栅格线名
- grid-column-start:列开始的栅格线名
- grid-column-end:列结束的栅格线名
- grid-row-start:行开始的栅格线名
- grid-row-end:行结束的栅格线名
通过四条边来定义子元素的具体位置,当未定义栅格线名时,可以使用1,2,3...作为栅格线名
.box1 {
grid-column-start:1;
grid-column-end:2;
grid-row-start:2;
grid-row-end:4;
background-color: #ff3426;//红色
}
.box2 {
grid-column-start:3;
grid-column-end:5;
grid-row-start:1;
grid-row-end:3;
background-color: #39f64f;//绿色
}
.parbox {
display:grid;
grid-template-columns: repeat(4,50px);
grid-template-rows: repeat(4,50px);
}
栅格线名可以为负数,表示从该栅格线往其反方向数
1. 栅格线的编号可以为负值,表示从倒数第n条线开始从后往前数
如:不知道栅格有几列,但想从最右边的栅格线开始部署,可以使用
grid-column-start:-1;
grid-row-start:-1;(行同理)
2. 如果为栅格线定义过名称,则可以使用该名称作为上述语句的值,如果变量对应的栅格线有多条,则使用变量名 序号来确定具体的栅格线,序号从1开始排列。如:有多条名为col-A的线,表示列从第4条col-A开始:
grid-column-start:col-A 4;
3. 此外可以使用span语句指定子元素跨越的行列数,如:
.box1 {
grid-column-start:1;
grid-column-end: span 1;
grid-row-start:2;
grid-row-end: span 2;
}
上述代码等同于:
.box1 {
grid-column-start:1;
grid-column-end: 2;
grid-row-start:2;
grid-row-end: 4;
}
表示该子元素从左边框号1开始,跨越1列,从上边框号2开始,跨越2行,其中span 1可以直接简写为span(默认为1),且span后的值不能为0或负值
4. 当使用 span 栅格线名 n 时,表示该元素跨越了n条该名称的栅格线
如:栅格部署为A、B栅格线交替命名时
A 格子 B 格子 A 格子 B 格子 A 格子 B 格子
此时
grid-column-start: A 1;
grid-column-end: span 2 A;
表示栅格从第1条A线开始,跨越1条名为A的栅格线,在下一个A线处结束
3.2 调用栅格线名的简写
上一节中 grid-column-start,grid-column-end和grid-row-start,grid-row-end用于指定栅格起始和结束的位置,该属性可以简写为
- grid-column: 起始栅格线/结束栅格线
- grid-row: 起始栅格线/结束栅格线
1. 元素开始和结束的栅格线名用 / 隔开
.box1 {
grid-column-start:1;
grid-column-end: 2;
grid-row-start:2;
grid-row-end: 4;
}
等价于
.box1 {
grid-column: 1 / 2;
grid-row: 2 / 4;
}
也可以用跨越了多少栅格表示
.box1 {
grid-column: 1 / span 1;
grid-row: 2 / span 2;
}
2. 如果 / 和第二个值省略,则默认起始结束的栅格线名都一致
如:列栅格线中有两条名为header的线,则
grid-column: header;
等价于
grid-column: header / header;
即以第一条header开始,第二条header结束,无论中间跨越多少栅格
3.3 grid-area
grid-area可用于调用网格线,也可用于为子元素命名
3.3.1 grid-area调用网格线
grid-column-start,grid-column-end和grid-row-start,grid-row-end可以直接用一个语句代替:
grid-area:行开始/列开始/行结束/列结束
如:
.box1 {
grid-row-start:2;
grid-row-end: 4;
grid-column-start:1;
grid-column-end: 2;
}
等价于
.box1 {
grid-area:2/1/4/2;
}
同样,值可以为跨越了多少个网格
.box1 {
grid-area: 2 / 1 / span 2 / span 1;
}
3.3.2 grid-area为子元素命名
可以通过grid-area给每个栅格子元素定义名称,然后由父容器通过grid-template-areas定义它们的排列方法
如:
.box1 {
grid-area: a;
}
.box2 {
grid-area: b;
}
.box3 {
grid-area: c;
}
.box4 {
grid-area: d;
}
.box5 {
grid-area: e;
}
.parbox {
display:grid;
grid-template-areas: 'a a a'
'b c d'
'b e e';
}
排列方法可以写于同一行上,但需要注意' '号
grid-template-areas: 'a a a''b c d''b e e';
变量名应该尽量使用有含义的单词
(子元素变量名应相应改变,这里只展示父容器属性)
.parbox {
display:grid;
grid-template-areas: 'header header header''left content right''left footer footer';
}
也可以省略其中的部分变量,使用...代替
.parbox {
display:grid;
grid-template-areas: 'header header header''left ... right''left footer footer';
}
4. 栅格的对齐方式
栅格对齐方式类似于flex弹性盒里的属性
属性 |
目标 |
适用于 |
justify-self |
行(一个栅格元素) |
子元素 |
justify-items |
行(所有栅格元素) |
父容器 |
justify-content |
行(整个栅格) |
父容器 |
align-self |
列(一个栅格元素) |
子元素 |
align-items |
列(所有栅格元素) |
父容器 |
align-content |
列(整个栅格) |
父容器 |
以行为例
.box1{
justify-self:start;
}
.box2{
justify-self:center;
}
.box3{
justify-self:end;
}
justify-self和justify-items用来调整单个或多个元素在它们自己栅格内的位置
当justify-self赋值为start、center、end时,如果子元素没有指定宽度和高度,则会自动缩为仅合适内容的大小,对齐方式同单词含义。赋值为stretch时会被拉伸,完全填充box(同剩下的box)
当需要所有元素都有该对齐方式,则可以给父容器添加justify-items和对应的值
box1
box2
box3
box4
box5
box6
box7
box8
box9
同样以行为例
.parbox{
width:260px;
height:260px;
display:grid;
grid-template-columns:repeat(3,80px);grid-template-rows:repeat(3,80px);
justify-content:center;
}
justify-content则是用来调整整个grid网格在父容器中的位置
box1
box2
box3
box4
box5
box6
box7
box8
box9
5. 隐式栅格
此前通过grid-template-rows定义的栅格为显式栅格,当一部分栅格超出了显式栅格,系统会将超出的那部分定义为隐式栅格。可以使用grid-auto-rows与grid-auto-columns定义隐式栅格的大小
如:
.grid{
display:grid;
width:200px;
height:200px;
//定义2*2的显式栅格
grid-template-columns:100px 100px;
grid-template-rows:100px 100px;
//定义隐式栅格尺寸(以行为例)
grid-auto-rows: 50px;
}
box1、box2、box3、box4在显式栅格内,高为100px,box5,box6超出了显式栅格,高将变为隐式栅格的高50px
box1
box2
box3
box4
box5
box6
6. 栅格流
栅格流主要分为优先行、优先列、密集流三种模式,由grid-auto-flow决定
grid-auto-flow的取值有row、column、dense(密集流)
.box{
display: grid;
grid-template: repeat(3,80px) / repeat(3,80px);
width: 240px;
height: 240px;
grid-auto-flow: row;
}
优先行与优先列的部署模型如下
密集流的主要作用是让元素尽量靠紧,因此有时会破坏栅格元素的顺序进行密集分布,向任何可以插入的位置安插合适的子元素
7. 错误处理
当输入错误的代码时,部分情况下grid会帮我们修正属性,但在有些情况下会抛弃部分无法解析的值,甚至不解析整个语句
1. 当栅格开始线放在结束线后
grid-row-start:5;
grid-row-end:2;
grid将修正为
grid-row-start:2;
grid-row-end:5;
2. 当栅格开始线和结束线都被声明为了跨度
grid-row-start: span ;
grid-row-end: span 3;
结束线的值将被修改为 auto
grid-row-start: span ;
grid-row-end: auto;
3. 如果栅格开始线被声明为跨越已命名的线,则该语句将被认为非法
grid-row-start: span header;
当栅格元素出现重叠时,可以使用 z-index 或 order 进行排序,并且栅格元素可以使用margin、position等标准流、定位等属性。并且还有其他一些更复杂的属性简写语法,本文不再展开说明,具体可以查阅MDN的文档