CSS进阶之Grid布局
FrankKai opened this issue · comments
在css-tricks的A Complete Guide to Flexbox一文中,有这样一句话:
Flexbox layout is most appropriate to the components of an application, and small-scale layouts, while the Grid layout is intended for larger scale layouts.
- flex布局适用于应用组件、小型布局,微观布局
- grid布局适用于更大型的布局,宏观布局
我一直以来觉得flex布局已经够用了,因此一直没有学习grid布局。
但是看到这句话,让我对grid产生了一些兴趣,到底grid是不是如作者所说:“grid适用于大型布局”,暂时先画一个问号“?”
当这篇博文结束时,相信对这个问号会有一个好的答案。
- 初识grid布局
- grid五大概念
- Grid container、Grid Tracks(fr、repeat()、显隐式grid、minmax)、Grid lines、Grid cells、Grid areas、Gutters
- 嵌套grid布局
- grid实现覆盖式的布局并通过z-index控制Grid层级、控制Grid顺序
初识grid布局
- CSS的grid布局,通过定义HTML元素的size,position和layer的关系,可以将一个页面划分成几个主要区域。
- CSS的grid布局,使作者能够将元素对齐成为列和行。很多情况下的布局,通过grid要比table布局简单得多。例如,一个grid容器的子元素可以定位自身,因此可以实现重叠和层级关系,这跟CSS定位元素是类似的
最简grid布局示例
<div class="wrapper">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
<div class="four">Four</div>
<div class="five">Five</div>
<div class="six">Six</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr); // 3是重复次数,fr是flex系数
grid-gap: 10px; // row-gap column-gap
grid-auto-rows: minmax(100px, auto); // 行的最小最大宽度
}
.one {
grid-column: 1 / 3; // grid-column-start, grid-column-end 从1开始到3结束(不包括3),可以理解成从1~3边区间内的面积。边的编号从1开始
grid-row: 1; // grid-row-start, grid-row-end 1,auto区间内的面积。边的编号从1开始
}
.two {
grid-column: 2 / 4;
grid-row: 1 / 3;
}
.three {
grid-column: 1;
grid-row: 2 / 5;
}
.four {
grid-column: 3;
grid-row: 3;
}
.five {
grid-column: 2;
grid-row: 4;
}
.six {
grid-column: 3;
grid-row: 4;
}
grid五大概念
- 固定和灵活的轨道尺寸(fixed flexible)
- 条目布局(item)
- 为已有内容增加额外的轨道(hold content)
- 对齐控制(alignment)
- 重叠内容控制(overlap)
固定和灵活的轨道尺寸
- 固定的轨道尺寸:可以理解为通过像素px创建网格,为网格设置了指定的大小
- 灵活的轨道尺寸:可以理解为通过百分比或者是全新的fr单位创建的网格
条目布局(item)
- 可以通过line number,name或者指定网格区域,将元素布局在网格的指定区域
- grid有自己的算法:即使没有明确指定位置,在网格上也可以布局元素
为已有内容增加额外的轨道(hold content)
- 可以在网格布局上定义明确的网格
- 网格布局很灵活,在需要时可以添加额外的列和行
- 包括“将尽可能多的列添加到容器”特性
对齐控制(alignment)
- 可以控制单个网格的对齐
- 可以控制整体网格的对齐
重叠内容控制(overlap)
- 一个网格上可以放置多个元素,可以部分重叠,可以通过z-index属性做重叠
- 当grid与其他的CSS类似flexbox结合时,可以构建出之前无法构建的布局
Grid container、Grid Tracks(fr、repeat()、显隐式grid、minmax)、Grid lines、Grid cells、Grid areas、Gutters
Grid container
- 通过display:grid或display:inline-grid可以创建出一个grid container
- 创建了grid container之后,所有grid container下属的子元素都成为了grid item
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
.wrapper{
display: grid;
}
通过为.wrapper设置display:grid属性,从默认的block变为grid,构建出一个grid container。
打开devtool选中某个grid item时,grid会有明显的虚线;普通布局不会有。
Grid Tracks
- 通过grid-template-columns和grid-template-rows定义行和列,叫做grid track,一个grid track指的是两条线之间的空间
- 与Grid track相关的概念还有:fr、repeat()函数、隐式grid和显式grid、track大小和minmax
row track和column track
可以通过grid-template-columns定义列track的宽度
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
.wrapper {
display: grid;
grid-template-columns: 200px 200px 200px;
}
fr、repeat()、显隐式grid、minmax
fr
track可以通过任何长度单位定义。
grid同样引入了一种特殊的长度单位去创建灵活的grid track。
这个单位就是fr,它代表的是网格容器中可用空间的一个部分。
下面的grid定义会创建三个等宽的track,宽度根据可用空间进行grow和shrink。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
如果1和4想占据2个单位的宽度的话,可以这样:
.wrapper {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
}
下面这样的如何表现呢?
.wrapper {
display: grid;
grid-template-columns: 500px 1fr 2fr;
}
第一个track 500px宽;剩余的空间3等分,按照1比2的比例分配出去。
repeat()函数
如果有很多重复的track的话,可以用repeat()函数来写。
例如下面的例子:
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
可以写成这样:
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
不仅仅可以单独使用repeat()函数,还可以与px以及其他的组合使用。
.wrapper {
display: grid;
grid-template-columns: 20px repeat(6, 1fr) 20px;
}
而且可以repeat多个track,例如下面这样:
5个1:2分割的track,总计10个。
.wrapper {
display: grid;
grid-template-columns: repeat(5, 1fr 2fr);
}
显隐式grid
- 如果只通过grid-template-columns去定义列track的话,grid也会同时创建行,这些行时是隐式grid布局形成的
- 显式的行grid和列grid,是通过grid-template-columns和grid-template-rows定义出来的
- 可以通过grid-auto-rows和grid-auto-columns定义隐式grid的tracks
这个例子通过grid-auto-rows,确保隐式的grid高度为200px。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 200px;
}
minmax
- 创建明确grid布局或者自动创建row和column时,我们希望给track一个最小的大小,同时希望任何添加的内容都能展开。例如,假设我想要我的行不比100像素小,但是我的内容最多拉伸到300像素高,就可以通过minmax()函数来实现。
- minmax()函数仅仅适用于grid布局。
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(100px, auto);
}
<div class="wrapper">
<div>One</div>
<div>Two
<p>I have some more content in.</p>
<p>This makes me taller than 100 pixels.</p>
</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
Grid lines
来看一个在这些属性上运用了grid line的例子:
- grid-column-start
- grid-column-end
- grid-row-start
- grid-row-end
<div class="wrapper">
<div class="box1">One</div>
<div class="box2">Two</div>
<div class="box3">Three</div>
<div class="box4">Four</div>
<div class="box5">Five</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
}
.box1 {
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 3;
}
.box2 {
grid-column-start: 1;
grid-row-start: 3;
grid-row-end: 5;
}
Grid cells
Grid areas
- grid item可以占据多个grid cell,row方向和column方向都行,占据了多个cell叫做area
- grid area必须是矩形,不能构建出L形的grid区域
Gutter
- 可以通过column-gap和row-gap为grid cell设置grid cell之间的间隙
- 通常为了布局美观,需要为grid container增加一个padding
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 10px;
row-gap: 1em;
}
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
嵌套grid布局
<div class="wrapper">
<div class="box box1">
<div class="nested">a</div>
<div class="nested">b</div>
<div class="nested">c</div>
</div>
<div class="box box2">Two</div>
<div class="box box3">Three</div>
<div class="box box4">Four</div>
<div class="box box5">Five</div>
</div>
.box1 {
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
display: grid;
grid-template-columns: repeat(3, 1fr);
}
- 通过
display: grid;grid-template-columns: repeat(3, 1fr);
将第一行内的子元素变为grid布局 - 通过
grid-row-start: 1;
控制box1的顺序;grid-row-start: 2;grid-row-start: 3;
可以将其放置在下面
grid-row-start: 2
grid-row-start: 3
grid实现覆盖式的布局并通过z-index控制Grid层级、控制Grid顺序
grid实现覆盖式的布局
grid布局不可做覆盖式的布局。
<div class="wrapper">
<div class="box box1">One</div>
<div class="box box2">Two</div>
<div class="box box3">Three</div>
<div class="box box4">Four</div>
<div class="box box5">Five</div>
</div>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
}
.box1 {
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 3;
}
.box2 {
grid-column-start: 1;
grid-row-start: 2;
grid-row-end: 4;
}
通过z-index控制Grid层级、控制Grid顺序
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
}
.box1 {
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 3;
z-index: 2;
}
.box2 {
grid-column-start: 1;
grid-row-start: 2;
grid-row-end: 4;
z-index: 1;
}
学习和实践感悟
- grid布局与flex布局最大的不同,在于实现多行布局更加便捷,这是因为在一个flex容器内,实现多行布局较为困难,而grid可以很方便的通过grid lines去划分自己占据的空间
- css tricks上的文章所说的 “grid布局适用于更大型的布局,宏观布局” ,这句话我认为是非常正确的;现代化的布局,应该是 “宏观grid + 微观flex布局” 的组合