CSS Grid,是CSS中最强大的二维布局系统,可以同时处理行和列,让复杂的网页布局变得简单优雅。
在CSS Grid出现之前,我们做网页布局,用的是table、float、position、inline-block这些方式。这些方式,要么语义不好,要么需要很多hack,要么实现复杂布局非常麻烦。后来有了Flexbox,一维布局变得简单了,但是二维布局(同时控制行和列)还是不够方便。
CSS Grid的出现,彻底改变了这一切。它是专门为二维布局设计的,可以轻松实现各种复杂的网页布局,而且代码简洁,语义清晰。
2017年,Chrome、Firefox、Safari、Edge等主流浏览器都开始支持CSS Grid。到了2018年,CSS Grid已经可以在生产环境中放心使用了。今天,我想从基础到高级,详细讲解一下CSS Grid的配置和使用。
一、CSS Grid的基本概念
在学习CSS Grid之前,先搞清楚几个基本概念:
1. 网格容器(Grid Container)
网格容器,就是应用了display: grid或者display: inline-grid的元素。它是所有网格项目的父元素。
.container {
display: grid;
}2. 网格项目(Grid Item)
网格项目,就是网格容器的直接子元素。注意,是直接子元素,孙子元素不会成为网格项目。
<div class="container">
<div class="item">1</div> <!-- 网格项目 -->
<div class="item">2</div> <!-- 网格项目 -->
<div class="item">3</div> <!-- 网格项目 -->
</div>3. 网格线(Grid Line)
网格线,是划分网格的线。水平的网格线划分行,垂直的网格线划分列。网格线是从1开始编号的,也可以用负数从后往前编号。
比如,一个3列2行的网格,就有4条垂直网格线(列线)和3条水平网格线(行线)。
4. 网格轨道(Grid Track)
网格轨道,是两条相邻网格线之间的空间。简单说,就是行和列。水平的轨道是行,垂直的轨道是列。
5. 网格单元格(Grid Cell)
网格单元格,是两条相邻行线和两条相邻列线交叉形成的空间,是网格中最小的单位。
6. 网格区域(Grid Area)
网格区域,是由任意多条网格线围成的矩形区域,可以包含一个或多个网格单元格。
二、网格容器的属性
网格容器的属性,是用来定义网格的整体结构的。下面逐个讲解:
1. display
定义一个网格容器。
.container {
display: grid; /* 块级网格容器 */
/* 或者 */
display: inline-grid; /* 行内网格容器 */
}2. grid-template-columns 和 grid-template-rows
这两个属性,用来定义网格的列和行的大小。
.container {
display: grid;
/* 定义3列,每列100px */
grid-template-columns: 100px 100px 100px;
/* 定义2行,第一行50px,第二行100px */
grid-template-rows: 50px 100px;
}除了固定的像素值,还可以用百分比、auto、fr等单位:
- 百分比:相对于网格容器的宽度/高度。
- auto:由内容自动决定大小。
- fr:fraction的缩写,表示剩余空间的比例。这是Grid中非常好用的一个单位。
.container {
display: grid;
/* 3列,第一列固定200px,剩余空间第二列占1份,第三列占2份 */
grid-template-columns: 200px 1fr 2fr;
/* 3行,高度自动 */
grid-template-rows: auto auto auto;
}还可以用repeat()函数简化重复的定义:
.container {
display: grid;
/* 重复3次,每次1fr,相当于 1fr 1fr 1fr */
grid-template-columns: repeat(3, 1fr);
/* 重复2次,每次100px 50px,相当于 100px 50px 100px 50px */
grid-template-columns: repeat(2, 100px 50px);
}3. grid-template-areas
这个属性,用来给网格区域命名,然后让网格项目引用这些区域名称来定位。这是CSS Grid中非常强大、非常直观的一个功能。
.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }上面的代码,就定义了一个经典的三列布局:头部占满一行,中间是侧边栏、主内容、右侧栏,底部占满一行。用grid-template-areas,布局结构一目了然,非常直观。
注意,用.可以表示一个空的单元格:
grid-template-areas:
"header header header"
"sidebar . aside"
"footer footer footer";中间的主内容区域是空的。
4. grid-column-gap / grid-row-gap / grid-gap
这三个属性,用来定义网格列之间和行之间的间距( gutter )。
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-column-gap: 20px; /* 列间距20px */
grid-row-gap: 10px; /* 行间距10px */
/* 或者用grid-gap简写,第一个是行间距,第二个是列间距 */
grid-gap: 10px 20px;
/* 如果只有一个值,行间距和列间距都是这个值 */
grid-gap: 15px;
}注意,这个间距只在网格项目之间,不会在容器边缘。
5. justify-items
定义网格项目在单元格内的水平对齐方式。
.container {
justify-items: start; /* 左对齐 */
justify-items: end; /* 右对齐 */
justify-items: center; /* 居中 */
justify-items: stretch; /* 拉伸填满(默认) */
}6. align-items
定义网格项目在单元格内的垂直对齐方式。
.container {
align-items: start; /* 顶部对齐 */
align-items: end; /* 底部对齐 */
align-items: center; /* 居中 */
align-items: stretch; /* 拉伸填满(默认) */
}7. place-items
justify-items和align-items的简写。
.container {
place-items: center center; /* 垂直居中,水平居中 */
place-items: center; /* 两个都是center */
}8. justify-content
当网格的总大小小于容器大小的时候,定义整个网格在容器内的水平对齐方式。
.container {
justify-content: start; /* 左对齐 */
justify-content: end; /* 右对齐 */
justify-content: center; /* 居中 */
justify-content: stretch; /* 拉伸 */
justify-content: space-around; /* 每个项目两侧间距相等 */
justify-content: space-between;/* 两端对齐,项目之间间距相等 */
justify-content: space-evenly; /* 所有间距相等 */
}9. align-content
类似justify-content,但是是垂直方向。
.container {
align-content: start;
align-content: end;
align-content: center;
align-content: stretch;
align-content: space-around;
align-content: space-between;
align-content: space-evenly;
}10. place-content
justify-content和align-content的简写。
11. grid-auto-columns / grid-auto-rows
当网格项目超出了显式定义的网格(也就是grid-template-columns/rows定义的范围),会自动创建隐式网格。这两个属性,用来定义隐式网格的列和行的大小。
.container {
display: grid;
grid-template-columns: 100px 100px; /* 显式定义2列 */
grid-auto-rows: 50px; /* 隐式行的高度都是50px */
}如果有3个项目,前两个在第一行,第三个会自动到第二行,第二行的高度就是50px。
12. grid-auto-flow
定义网格项目的自动排列方向。
.container {
grid-auto-flow: row; /* 按行排列(默认),排满一行换下一行 */
grid-auto-flow: column; /* 按列排列,排满一列换下一列 */
grid-auto-flow: row dense; /* 按行排列,并且尽量填满空隙 */
}dense关键字,可以让后面的小项目往前填充前面留下的空隙,让网格更紧凑。
三、网格项目的属性
网格项目的属性,是用来控制单个项目在网格中的位置和大小的。
1. grid-column-start / grid-column-end / grid-row-start / grid-row-end
这四个属性,用来定义网格项目占据哪些网格线。
.item {
grid-column-start: 1; /* 从第1条列线开始 */
grid-column-end: 3; /* 到第3条列线结束(占2列) */
grid-row-start: 1; /* 从第1条行线开始 */
grid-row-end: 2; /* 到第2条行线结束(占1行) */
}还可以用span关键字,表示跨越多少个轨道:
.item {
grid-column-start: 1;
grid-column-end: span 2; /* 跨越2列 */
/* 或者 */
grid-column: 1 / span 2; /* 简写 */
}也可以用网格区域的名称:
.item {
grid-column-start: header-start;
grid-column-end: header-end;
}2. grid-column / grid-row
上面四个属性的简写。
.item {
grid-column: 1 / 3; /* 从第1条列线到第3条列线 */
grid-row: 1 / 2; /* 从第1条行线到第2条行线 */
grid-column: 1 / span 2; /* 从第1条列线开始,跨越2列 */
}3. grid-area
给网格项目命名,或者引用grid-template-areas中定义的区域名称。
/* 引用区域名称 */
.item {
grid-area: header;
}
/* 也可以用四个值,分别是 row-start / column-start / row-end / column-end */
.item {
grid-area: 1 / 1 / 2 / 3;
}4. justify-self
定义单个网格项目在单元格内的水平对齐方式,会覆盖容器的justify-items。
.item {
justify-self: start;
justify-self: end;
justify-self: center;
justify-self: stretch;
}5. align-self
定义单个网格项目在单元格内的垂直对齐方式,会覆盖容器的align-items。
.item {
align-self: start;
align-self: end;
align-self: center;
align-self: stretch;
}6. place-self
justify-self和align-self的简写。
7. z-index
网格项目可以重叠,用z-index控制重叠时的层级。
.item-a {
grid-column: 1 / 3;
grid-row: 1 / 2;
z-index: 1;
}
.item-b {
grid-column: 2 / 4;
grid-row: 1 / 2;
z-index: 2; /* b在a上面 */
}四、常见布局实现
了解了基本属性之后,我们来看看用CSS Grid怎么实现一些常见的布局。
1. 三列布局(侧边栏+主内容+右侧栏)
.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
min-height: 100vh;
}2. 响应式卡片布局
用auto-fill和minmax(),可以实现自动适应容器宽度的卡片布局,不需要媒体查询。
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-gap: 20px;
}这个布局的意思是:每列最小250px,最大1fr(平分剩余空间),自动填充尽可能多的列。容器宽的时候列多,容器窄的时候列少,自动响应式。
auto-fill和auto-fit的区别:auto-fill会保留空的列轨道,auto-fit会把空的列轨道折叠,让现有项目拉伸填满。大部分时候用auto-fit效果更好。
3. 圣杯布局
.container {
display: grid;
grid-template: auto 1fr auto / 200px 1fr 200px;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
min-height: 100vh;
}4. 瀑布流布局(近似)
CSS Grid可以做近似的瀑布流布局(严格的瀑布流需要CSS Masonry,目前还在实验阶段):
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
grid-gap: 10px;
}
.item:nth-child(3n+1) { grid-row: span 2; }
.item:nth-child(3n+2) { grid-row: span 3; }五、高级技巧和最佳实践
1. 用fr单位做灵活布局
fr单位是CSS Grid的一大亮点,可以轻松实现各种灵活的比例布局。比如,一个经典的布局:侧边栏固定宽度,主内容自适应。
.container {
display: grid;
grid-template-columns: 250px 1fr;
}再比如,三列等宽:
grid-template-columns: repeat(3, 1fr);2. 用minmax()做最小最大限制
minmax(min, max)函数,可以定义轨道的最小和最大尺寸。
grid-template-columns: minmax(200px, 1fr) 2fr;第一列最小200px,最大1fr。这样,容器很窄的时候,第一列也不会小于200px。
3. 用auto-fit + minmax做无媒体查询的响应式
前面提到过,这是CSS Grid中最实用的技巧之一:
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}不需要任何媒体查询,就能实现从1列到多列的自动响应式布局。
4. 用grid-template-areas做语义化布局
grid-template-areas让布局结构在CSS中一目了然,非常直观,也方便维护和修改。推荐在做整体页面布局的时候使用。
5. Grid和Flex配合使用
Grid和Flex不是互斥的,而是互补的。Grid适合做整体的二维页面布局,Flex适合做一维的组件内部布局。最佳实践是:外层用Grid做页面整体布局,内层组件用Flex做内部排列。
6. 注意浏览器兼容性
到2018年,主流浏览器的最新版本都已经支持CSS Grid了。但是,如果需要兼容旧版本浏览器(比如IE11),需要注意:
- IE11支持的是旧版本的Grid语法,和新标准有差异。
- 可以用Autoprefixer自动处理IE11的前缀和语法转换。
- 如果不需要兼容IE11,可以放心使用标准的Grid语法。
7. 用命名网格线提高可维护性
可以给网格线命名,然后用名称来定位项目,比用数字更语义化:
.container {
grid-template-columns: [sidebar-start] 200px [sidebar-end main-start] 1fr [main-end];
}
.sidebar {
grid-column: sidebar-start / sidebar-end;
}六、写在最后
CSS Grid,是CSS布局的一次革命。它让复杂的二维网页布局变得简单、优雅、可维护。
在CSS Grid之前,我们做布局,需要用各种hack,需要写很多冗余的代码,需要处理各种浏览器兼容性问题。有了CSS Grid,很多以前需要花半天才能实现的布局,现在几行代码就能搞定。
当然,CSS Grid的属性比较多,刚开始学的时候可能会觉得有点复杂。但是,只要掌握了核心的几个属性(grid-template-columns/rows、grid-template-areas、grid-gap、grid-column/row),就能应对大部分布局场景了。其他的属性,可以在需要的时候再查文档学习。
2018年,CSS Grid已经足够成熟,可以在生产环境中放心使用了。如果你还没有用过CSS Grid,强烈建议你尝试一下。用过之后,你可能就再也回不到float布局的时代了。
最后,用一句话来总结这篇文章:"CSS Grid是目前最强大的CSS二维布局系统,掌握了它,网页布局就不再是难题。从基础的容器和项目属性,到高级的响应式技巧,循序渐进地学习和实践,你就能熟练运用CSS Grid,构建出优雅、灵活、可维护的网页布局。"
希望这篇文章,能帮助你入门和掌握CSS Grid。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录