Grid布局
grid布局是一种新的布局方案。传统布局使用浮动和定位,而grid布局可以像表格一样将页面容器分割成一块一块的区域,定义子元素的排布和位置。可以说是flex布局的升级版。
借用大神旭哥的话:
Grid布局就像是“分田种地”。故事是这样的,张老板是个程序员,省吃俭用攒了点小钱,然后老家因为城镇化建设,农村都没什么人,土地都荒废在那里,于是就承包了一块地,打算养养鱼,种种果树。承包的地方很挺大,如何划分土地就成了问题,于是张老板打算借助Grid布局来划分。
对于身为码农的我们来说,种地就对了!
兼容性
Grid布局是微软在2010年提出来的一种新的布局方式,到2016年的时候提交了该布局的草案。经过近几年发展,兼容性越来越好。
引用自 Can I Use 。兼容火狐52+、谷歌57+等现代浏览器,IE10和11需要添加-ms-来实现兼容。
名词概念
Grid Container、Grid Items(网格容器、网格项)
元素应用 display: grid;
即成为网格容器,它是所有网格项的父元素。
很好理解,下面这个例子,class为container的div设置了 display: grid;
,container就是网格容器,里面的item都是网格项。
<style>
.container{ display: grid; }
</style>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>
Grid Lines(网格线)
所谓的网格都是由横向和竖向的若干线交错产生的,这些线就是网格线。
熟知数学的我们知道,正常情况下,n行有n + 1根水平网格线,m列有m + 1根垂直网格线,比如三行就有四根水平网格线。
网格线是定义容器的时候产生的,和网格项没有直接的关系,网格项是直接存在于html中的,但是网格线正常看不到它。说白了网格线是虚拟的。
Grid Track(网格轨道)
两个相邻的网格线之间为网格轨道。
网格轨道的特点是能接触到网格容器的边缘。
Grid Cell(网格单元)
两个相邻的列网格线和两个相邻的行网格线之间的空间为网格单元,类似于excel中的单元格。
Grid Areas(网格区域)
四条网格线包围的地方称为网格区域,类似于excel中的合并单元格。
关键字
fr(剩余空间分配数)
fr单位被用于在一系列长度值中分配剩余空间,如果多个已指定了多个部分,则剩下的空间根据各自的数字按比例分配。
gr(网格数)
目前未被w3c采纳,可以作为了解。
属性
介绍完概念,进入正题。
gird布局的属性可以分为两类:容器属性和项目属性。
容器属性分为这几类:
- display:布局方式
- grid-template:定义网格线的名称和网格轨道的尺寸大小
- gap:定义网格项之间的间隙
- items:定义网格单元内容的位置
- content:定义整个内容区域在容器里面的位置
- grid-auto:定义多余网格的大小
- grid-auto-flow:定义网格项的放置顺序
项目属性分为这几类:
- column / row:指定项目位于哪(些)条网格线
- area:指定项目放在哪一个区域
- self:指定网格单元内容的位置
下面来看具体的使用
容器属性
1. display
有三种取值:grid | inline-grid | subgrid
gird:生成块级网格
inline-grid: 生成行内网格
subgrid: 网格容器本身就是网格项(嵌套网格容器),此属性用来继承其父网格容器的行、列大小。(目前所有浏览器都不兼容)
注意,设为网格布局以后,容器子元素(项目)的float、display: inline-block、display: table-cell、vertical-align和column-*等设置都将失效。但是position是不会失效的。
2.1 grid-template-columns和grid-template-rows
grid-template-columns用来定义每一列的宽度,grid-template-rows用来定义每一行的高度。
.container{
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
}
上面这个例子,就是一个三行五列的网格布局。
- grid-template-columns的取值可以是绝对长度(px、em)、百分比、auto、fr、函数。
- auto表示由浏览器自己决定长度。
函数&关键字:
$minmax(min, max):$
- 用来定义一个范围,最小值为min,最大值为max。
- max可以设置为fr,min不可以。
- 如果max值小于min值,则该值会被视为min值。
.container{
grid-template-columns: 40px 50px minmax(50px, 2fr) 1fr 40px;
grid-template-rows: 25% 100px auto;
}
$repeat(repeat, values):$
- 表示轨道列表的重复片段,允许以更紧凑的形式写入大量显示重复模式的列或行。
- 第一个值repeat可以是固定的数字(n),表示重复n次,也可以是
auto-fit
或auto-fill
,表示自动填充,容纳不下的放到下一行。
例如:
/* css */
.container{
width: 800px;
height: 300px;
display: grid;
grid-template-columns: repeat(auto-fit, 200px);
grid-template-rows: auto auto;
gap: 5px;
}
<!--html-->
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
</div>
这里有两点要注意:
- 布局设置的是两行,最终由于单个轨道容纳不下,最终变成4行。多出的这两行可以用
grid-auto-rows
来进行设置,这个属性后面会讲到。 auto-fit
和auto-fill
通常是没有区别的,只有在容器宽度大于子元素的最小宽度总和时才有显示区别。
我们来把上面的例子稍微改动一下,
.container{
grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
}
我们再看一下auto-fit
。
.container{
grid-template-columns: repeat(auto-fit, minmax(50px, 1fr));
}
可以发现,使用auto-fill
的网格宽度为52.5px,auto-fit
的网格宽度为75.5px
这个值我们可以计算一下
假设一行有n个单元格,两个单元格之间的间隙是5
所以 $50n + 5(n - 1) = 800$,n ≈ 14.6,向下取整得到14
有了列数,假设单元格宽度为 $x$ 带入上面这个式子:$14x + 5*13 = 800$,得到单元格宽度为52.5px
。
由此可知
auto-fit
和auto-fill
都会以最小的宽度创建单元格,创建完成以后,如果有多余的单元格,auto-fit
会把这些多余的单元格均分给每一网格项,再重新创建单元格,而auto-fill
不会。- 需要注意的是:只有在容器宽度大于子元素的最小宽度总和时才会这样,除此之外两者的显示是一样的。
网格线名称:
grid-template-columns属性里面,还可以使用方括号,指定每一根网格线的名字,方便以后的引用。
名字可以写多个,用空格隔开。
.container{
grid-template-columns: [c1 r1] 40px [c2] 50px [c3] auto [c4] 50px [c5] 40px;
grid-template-rows: 25% 100px auto;
}
grid-template-rows的用法与grid-template-columns完全一样。
2.2 grid-template-areas
areas是区域的意思,grid-template-areas用来给各个网格单元命名,就像给网格线命名一个道理。写法上类似于矩阵。
.container{
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
grid-template-areas:
'a a a b b'
'c c d . e'
'c c d . e';
}
上面这个例子将网格分为a、b、c、d、e五个区域。如果某些区域不需要利用,则使用"点"(.)表示。
需要注意:
- 写法上分号的位置,最后单元格的末尾才加分号。
- 多个同名的,跨越相邻行或列的单元称为网格区块(grid area)。非矩形的网格区块是无效的。
- 网格区块会影响到网格线。每个区块的起始网格线,会自动命名为区块名-start,终止网格线自动命名为区块名-end。上面例子中,第一行第3、4列间的网格线自动命名为
a-end
和b-start
,水平网格线亦同理。 - 网格的命名并不会马上影响网格项的显示,需要使用项目属性指定其位置才可以,项目属性下面会讲到。
2.3 grid-template
grid-template属性是grid-template-columns、grid-template-rows和grid-template-areas这三个属性的合并简写形式。
语法是 grid-template: <'grid-template-rows'> / <'grid-template-columns'>
.container {
display: grid;
width: 100%;
height: 200px;
grid-template: [header-left] "head head" 30px [header-right]
[main-left] "nav main" 1fr [main-right]
[footer-left] "nav foot" 30px [footer-right]
/ 120px 1fr;
}
先写行属性,再写列属性,中间用 /
隔开,从易读性考虑,不建议这样写。
3. grid-gap
grid-row-gap 属性是用来设置网格行与行之间的间隙,grid-column-gap 属性是用来设置网格列与列之间的间隙。
.container{
display: grid;
grid-template-columns: repeat(auto-fit, 200px);
grid-template-rows: auto auto;
grid-row-gap: 20px;
grid-column-gap: 10px;
}
上面的代码设置列间隙为10px,行间隙为20px。
grid-gap是 grid-row-gap 和 grid-column-gap的简写形式,语法如下:
grid-gap:<row-gap> <column-gap>
如果省略了第二个值,浏览器认为第二个值等于第一个值。
根据最新标准,上面三个属性名的grid-前缀已经删除,grid-column-gap和grid-row-gap写成column-gap和row-gap,grid-gap写成gap。
但是为了兼容浏览器,比如火狐52-61,还需要使用带有前缀的属性。
4.1. justify-items和align-items
justify-items 定义了网格布局中项目的水平对齐方式,align-items 定义了竖直对齐方式。
这个与flex布局的有些区别,flex布局的对齐方式分主轴和交叉轴,主轴方向的改变影响属性作用的方向。而grid布局是二维的,行列方向是固定的,所以说到 justify 一定就是指行(水平)方向,align就是指列(竖直)方向。
属性值:
- start:内容与网格区域的左端对齐
- end: 内容与网格区域的右端对齐
- center: 内容位于网格区域的中间位置
- stretch: 内容宽度占据整个网格区域空间(默认值)
上图显示了justify-items不同取值的结果,align-items与justify-items效果一样,只是作用的方向不同。
4.2. place-items
place-items属性是align-items属性和justify-items属性的合并简写形式。
语法是 place-items: <align-items> <justify-items>;
如果省略第二个值,则浏览器认为与第一个值相等。
.container{
display: grid;
grid-template-columns: repeat(auto-fit, 200px);
grid-template-rows: auto auto;
place-items: center center;
}
有了这个属性,水平垂直居中就很容易了。
5.1. justify-content和align-content
justify-content定义了网格容器中,网格区域在水平方向上的对齐方式,align-content定义了网格区域在竖直方向上的对齐方式。
属性值比items要多:
- start:网格区域与容器的左端对齐
- end: 网格区域与容器的右端对齐
- center: 网格区域位于容器的中间位置
- stretch: 网格区域占据整个容器空间(默认值)
- space-around:网格项之间设置等宽的间隙,与容器边框的间隙是项之间间隙的一半
- space-between: 网格项之间设置等宽的间隙,与容器边框没有间隙
- space-evenly:网格项之间和与容器边框设置等宽的间隙
与items一样,上图显示了justify-content不同取值的结果,align-content与justify-content效果一样,只是作用的方向不同。
5.2. place-content
place-content属性是align-content属性和justify-content属性的合并简写形式。
语法是 place-content: <align-content> <justify-content>;
如果省略第二个值,则浏览器认为与第一个值相等。
.container{
display: grid;
grid-template-columns: repeat(auto-fit, 200px);
grid-template-rows: 100px 100px;
place-content: space-around space-evenly;
}
6. grid-auto-columns和grid-auto-rows
指定自动生成的网格轨道的大小。
当定义的网格不够容纳所有网格项,多出的网格项另起一行排列,或者给某一个网格项指定到定义好的网格区域的外部,这个时候,浏览器会自动生成多余的网格,以便放置项目。
grid-auto-columns和grid-auto-rows就可以用来定义这些自动生成的多余的网格的大小。
.container{
width: 500px;
height: 400px;
display: grid;
grid-template-columns: 40px auto 50px 40px;
grid-template-rows: 200px auto;
grid-auto-columns: 50px;
grid-gap: 5px;
}
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
</div>
如上面的代码所示,定义的网格是2行4列一共8个单元格,但是网格项有10个,所以最终生成的网格是3行4列,grid-auto-columns: 50px;
让最后一行的行高为50px。
grid-auto-columns和grid-auto-rows的默认值为auto
。
7. grid-auto-flow
属性控制着自动布局算法怎样运作,精确指定在网格中被自动布局的元素怎样排列。
语法为 grid-auto-flow: [ row | column ] || dense
属性值
- row: 指定自动布局算法按照通过逐行填充来排列元素,在必要时增加新行。(默认值)
- column:指定自动布局算法通过逐列填充来排列元素,在必要时增加新列。
- dense: 指定自动布局算法使用一种“稠密”堆积算法,如果后面出现了稍小的元素,则会试图去填充网格中前面留下的空白。
dense的意思即填充元素的时候,轮到一个元素了,发现这个格子放不下了,这个元素就被放到了新一行,如果没有dense的话这个格子就空着了,加上dense的话,这个格子就会找其它能放下的元素放在这里。
这样做会填上稍大元素留下的空白,但同时也可能导致原来出现的次序被打乱。
博主不建议使用隐式的网格,即不建议使子元素超出定义的网格区域,也不建议使用grid-auto-flow,尤其dense属性值,会让布局变得难以控制。
项目属性
1.1. grid-column-start和grid-column-end和grid-row-start和grid-row-end
这四个属性用来指定网格项在网格中的位置。从意思上就很明确。
- grid-column-start:项目左边框的位置
- grid-column-end:项目右边框的位置
- grid-row-start:项目上边框的位置
- grid-row-end:项目下边框的位置
可以指定的有网格线数字(1、2、3...的顺序)、网格线名称(之前命过名的话)、span(跨越)
语法为: <name> | <number> | span <number>
.container{
width: 600px;
height: 400px;
display: grid;
grid-template-columns: 200px 1fr;
grid-auto-rows: 80px 1fr 1fr;
grid-gap: 10px;
}
.item {
background: skyblue;
}
.toolbar{
grid-column-start: 1;
grid-column-end: 3;
}
.tree{
grid-row-start: 2;
grid-row-end: 4;
}
<div class="container">
<div class="item toolbar">toolbar</div>
<div class="item tree">tree</div>
<div class="item table">table</div>
<div class="item subtable">subtable</div>
</div>
上面的代码所示的就是一个典型的布局,通过定义toolbar元素和tree元素的开始结束位置,达到占用多个单元的目的。
使用span
关键字也可以实现,span
表示"跨越",即左右边框(上下边框)之间跨越多少个网格。
.toolbar{
grid-column-start: 1;
grid-column-end: span 2;
}
.tree{
grid-row-start: 2;
grid-row-end: span 2;
}
1.2. grid-row和grid-column
grid-row是grid-row-start和grid-row-end的简写形式。
grid-column是grid-column-start和grid-column-end的简写形式。
语法为:<start-line> / <end-line>
.toolbar{
grid-column: 1 / span 2;
}
.tree{
grid-row-start: 2 / span 2;
}
2. grid-area
grid-area属性指定项目放在哪一个区域。
我们肯定还记得前面的这个属性grid-template-areas
,给容器划分区域并命名,命名完成以后,使用grid-area
属性就可以指定项目放到哪里了。
还是刚才那个典型布局,这次我们用grid-area
属性来试试。
.container{
width: 600px;
height: 400px;
display: grid;
grid-template-columns: 200px 1fr;
grid-auto-rows: 80px 1fr 1fr;
grid-gap: 10px;
grid-template-areas:
"toolbar toolbar"
"tree table"
"tree subtable";
}
.item {
background: skyblue;
}
.toolbar{
grid-area: toolbar;
}
.tree{
grid-area: tree;
}
<div class="container">
<div class="item toolbar">toolbar</div>
<div class="item tree">tree</div>
<div class="item table">table</div>
<div class="item subtable">subtable</div>
</div>
可以看到,效果跟刚才是一样的。
我们需要注意的是:
- 我们给容器划分区域,但是网格是不变的。
- 如果多个项目放在同一个位置,这些项目会重叠,可以使用z-index指定哪个在上面显示。使用这个功能实现选项卡的切换也很方便。
3.1 justify-self和align-self
justify-self设置元素中内容的水平对齐方式。align-self设置元素中内容的竖直对齐方式。
- start:内容与网格项的左端对齐
- end: 内容与网格项的右端对齐
- center: 内容位于网格项的中间位置
- stretch: 内容宽度占据整个网格项空间(默认值)
3.2 place-self
place-self属性是align-self属性和justify-self属性的合并简写形式。
语法为:<align-self> <justify-self>
.item {
place-self: center center
}
如果省略第二个值,place-self属性会认为这两个值相等。
结束
以上就是grid布局的简单介绍~~
参考内容:
mdn api: https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Grid_Layout
阮一峰CSS Grid 网格布局教程:http://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html