CSS Grid 布局是 CSS 中最强大的布局系统。与 flexbox 的一维布局系统不同,CSS Grid 布局是一个二维布局系统,也就意味着它可以同时处理列和行。通过将 CSS 规则应用于 父元素 (成为 Grid Container 网格容器)和其 子元素(成为 Grid Items 网格项),你就可以轻松使用 Grid(网格) 布局。
简介
CSS Grid(网格) 布局(又称为 “Grid(网格)” ),是一个二维的基于网格的布局系统,它的目标是完全改变我们基于网格的用户界面的布局方式。CSS 一直用来布局我们的网页,但一直以来都存在这样或那样的问题。一开始我们用表格(table),然后是浮动(float),再是定位(postion)和内嵌块(inline-block),但是所有这些方法本质上都是只是 hack 而已,并且遗漏了很多重要的功能(例如垂直居中)。Flexbox 的出现很大程度上改善了我们的布局方式,但它的目的是为了解决更简单的一维布局,而不是复杂的二维布局(实际上 Flexbox 和 Grid 能协同工作,而且配合得非常好)。Grid(网格) 布局是第一个专门为解决布局问题而创建的 CSS 模块
基础知识和浏览器支持
首先,你必须使用 display: grid 将容器元素定义为一个 grid(网格) 布局,使用 grid-template-columns 和 grid-template-rows 设置 列 和 行 的尺寸大小,然后通过 grid-column 和 grid-row 将其子元素放入这个 grid(网格) 中。与 flexbox 类似,网格项(grid items)的源(HTML结构)顺序无关紧要。你的 CSS 可以以任何顺序放置它们,这使得使用 媒体查询(media queries)重新排列网格变得非常容易。定义整个页面的布局,然后完全重新排列布局以适应不同的屏幕宽度,这些都只需要几行 CSS ,想象一下就让人兴奋。Grid(网格) 布局是有史以来最强大的 CSS 模块之一。
截至2017年3月,许多浏览器都提供了对 CSS Grid 的原生支持,而且无需加浏览器前缀:Chrome(包括 Android ),Firefox,Edge,Safari(包括iOS)和 Opera 。 另一方面,Internet Explorer 10和11支持它,但是是一个过时的语法实现。 现在是时候使用 Grid 布局网页了!
这个浏览器支持 CSS Grid 的数据,来自 Caniuse ,你可以查看更多的细节。 数字表示支持以上功能的浏览器版本号。
除了微软之外,浏览器厂商似乎还没有对 Grid(网格) 搞自己的一套实现(比如加前缀),直到规范完全成熟。这是一件好事,因为这意味着我们不必担心学习多个语法。
在生产中使用 Grid 只是时间问题。 但现在是学习的时候了。
重要术语
在深入了解 Grid 的概念之前,理解术语是很重要的。由于这里涉及的术语在概念上都很相似,如果不先记住 Grid 规范定义的含义,很容易混淆它们。但是别担心,术语并不多。
网格容器(Grid Container)
应用 display: grid 的元素。这是所有 网格项(grid item)的直接父级元素。在这个例子中,container 就是 网格容器(Grid Container)。
HTML 代码:
网格项(Grid Item)
网格容器(Grid Container)的子元素(例如直接子元素)。这里 item 元素就是网格项(Grid Item),但是 sub-item 不是。
HTML 代码:
网格线(Grid Line)
网格轨道(Grid Track)
两条相邻网格线之间的空间。你可以把它们想象成网格的列或行。下图是第二条和第三条 行网格线 之间的 网格轨道(Grid Track)。
网格单元格(Grid Cell)
两个相邻的行和两个相邻的列网格线之间的空间。这是 Grid(网格) 系统的一个“单元”。下图是第 1 至第 2 条 行网格线 和第 2 至第 3 条 列网格线 交汇构成的 网格单元格(Grid Cell)。
网格区域(Grid Area)
4条网格线包围的总空间。一个 网格区域(Grid Area) 可以由任意数量的 网格单元格(Grid Cell) 组成。下图是 行网格线1和3,以及列网格线1和3 之间的网格区域。
Grid(网格) 属性目录
网格容器(Grid Container) 属性
display
grid-template-columns
grid-template-rows
grid-template-areas
grid-template
grid-column-gap
grid-row-gap
grid-gap
justify-items
align-items
place-items
justify-content
align-content
place-content
grid-auto-columns
grid-auto-rows
grid-auto-flow
grid
网格项(Grid Items) 属性
grid-column-start
grid-column-end
grid-row-start
grid-row-end
grid-column
grid-row
grid-area
justify-self
align-self
place-self
display
将元素定义为网格容器,并为其内容建立新的 网格格式上下文。
值:
CSS 代码:
.container {
display: grid | inline-grid;
}
grid-template-columns / grid-template-rows
使用空格分隔的值列表,用来定义网格的列和行。这些值表示 网格轨道(Grid Track) 大小,它们之间的空格表示网格线。
值:
– track-size: 可以是长度值,百分比,或者等份网格容器中可用空间(使用 fr 单位)
– line-name:你可以选择的任意名称
CSS 代码:
.container {
grid-template-columns: ... | ...;
grid-template-rows: ... | ...;
}
示例:
当你在 网格轨道(Grid Track) 值之间留出空格时,网格线会自动分配正数和负数名称:
CSS 代码:
.container {
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
}
但是你可以明确的指定网格线(Grid Line)名称,例如 值。请注意网格线名称的括号语法:
CSS 代码:
.container {
grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}
请注意,一条网格线(Grid Line)可以有多个名称。例如,这里的第二条 行网格线(row grid lines) 将有两个名字:row1-end 和 row2-start :
CSS 代码:
.container {
grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end];
}
如果你的定义包含多个重复值,则可以使用 repeat() 表示法来简化定义:
CSS 代码:
.container {
grid-template-columns: repeat(3, 20px [col-start]);
}
上面的代码等价于:
CSS 代码:
.container {
grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start];
}
如果多行共享相同的名称,则可以通过其网格线名称和计数来引用它们。
CSS 代码:
.item {
grid-column-start: col-start 2;
}
fr 单元允许你用等分网格容器剩余可用空间来设置 网格轨道(Grid Track) 的大小 。例如,下面的代码会将每个网格项设置为网格容器宽度的三分之一:
CSS 代码:
.container {
grid-template-columns: 1fr 1fr 1fr;
}
剩余可用空间是除去所有非灵活网格项 之后 计算得到的。在这个例子中,可用空间总量减去 50px 后,再给 fr 单元的值 3 等分:
CSS 代码:
.container {
grid-template-columns: 1fr 50px 1fr 1fr;
}
常用Grid布局属性介绍
下面从一个简单Grid布局例子说起。
CSS Grid 布局由两个核心组成部分是 wrapper(父元素)和 items(子元素)。 wrapper 是实际的 grid(网格),items 是 grid(网格) 内的内容。
下面是一个 wrapper 元素,内部包含6个 items :
1
2
3
4
5
6
要把 wrapper 元素变成一个 grid(网格),只要简单地把其 display 属性设置为 grid 即可:
.item1{
background: red;
}
.item2{
background:orange;
}
.item3{
background: yellow;
}
.item4{
background: green;
}
.item5{
background: rgb(0, 247, 255);
}
.item6{
background: blue;
}
/* 创建一个 3x3 的grid(网格) */
.wrapper{
display: grid;
}
Columns(列) 和 rows(行)
为了使其成为二维的网格容器,我们需要定义列和行。让我们创建3列和2行。我们将使用grid-template-row和grid-template-column属性。
.wrapper{
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 50px 50px;
}
grid-template-columns的3个值表示三列,相应的数值表示列宽即都为100px。
grid-template-rows的2个值表示两行,相应的数值表示行高即都为50px
我们可以变化一下行高跟列宽的值看下效果,代码:
.wrapper{
display: grid;
grid-template-columns: 200px 50px 100px;
grid-template-rows: 100px 30px;
}
1
2
3
4
5
6
创建一个 3×3 的 grid(网格):
.wrapper{
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
}
得到如下效果:
我们只在页面上看到 3×2 的 grid(网格),而我们定义的是 3×3 的 grid(网格)。这是因为我们只有 6 个 items(子元素) 来填满这个网格。如果我们再加3个 items(子元素),那么最后一行也会被填满。
要定位和调整 items(子元素) 大小,我们将使用 grid-column 和 grid-row 属性来设置:
.item1{
background: red;
grid-column-start : 1;
grid-column-end: 4;
/* 或者如下写法 */
/* grid-column: 1/4; */
}
上面代码意思就是: item1 占据从第一条网格线开始,到第四条网格线结束。显示效果如下:
如果你不明白我们设置的只有 3 列,为什么有4条网格线呢?看看下面这个图像,黑色的列网格线你就明白了:
如果上面的看懂了,来个复杂点的巩固下。
.item1{
background: red;
grid-column-start : 1;
grid-column-end: 3;
/* 或者如下写法 */
/* grid-column: 1/4; */
}
.item2{
background:orange;
}
.item3{
background: yellow;
grid-row-start:2;
grid-row-end: 4;
}
.item4{
background: green;
grid-column-start:2;
grid-column-end:4;
}
.item5{
background: rgb(0, 247, 255);
}
.item6{
background: blue;
}
/* 创建一个 3x3 的grid(网格) */
.wrapper{
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
}
.header{
background: red;
}
.menu{
background: yellow;
}
.content{
background: green;
}
.footer{
background: gray;
}
.container{
display: grid;
grid-template-columns: repeat(12,1fr);
grid-template-rows:50px 350px 50px;
grid-gap: 5px;
}
HEADER
CONTENT
使用 grid-template-columns 属性创建一个 12 列的网格,每个列都是一个单位宽度(总宽度的 1/12 )。(愚人码头注:其中, repeat(12, 1fr) 意思是 12 个重复的 1fr 值。 fr 是网格容器剩余空间的等分单位。)
使用 grid-template-rows 属性创建 3 行,第一行高度是 50px ,第二行高度是 350px 和第三行高度是 50px。
使用 grid-gap 属性在网格中的网格项之间添加一个间隙。
添加 grid-template-areas
这个属性被称为网格区域,也叫模板区域,能够让我们轻松地进行布局实验。
要将它添加到网格中,我们只需给网格容器加一个 grid-template-areas 属性即可。 语法可能有点奇怪,因为它不像其他的 CSS 语法。例如:
.container {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 50px 350px 50px;
grid-template-areas:
"h h h h h h h h h h h h"
"m m c c c c c c c c c c"
"f f f f f f f f f f f f";
}
上面代码创建3行12列,上面grid-template-areas属性中的值,每行代表一行,用网格术语来说是 网格轨道(Grid Track) ,每个字符( h,m,c,f)代表一个网格单元格。愚人码头注:其实是 网格区域(Grid Area) 名称,你可以使用任意名称。
你可能已经猜到,我选择了字符 h,m,c,f,是因为他们是 header, menu, content 和 footer 的首字母。 当然,我可以把它们叫做任何想要的名称,但是使用他们所描述的东西的第一个字符更加容易让人理解。
给网格项设定网格区域名称
现在我们需要将这些字符与网格中的网格项建立对应的连接。 要做到这一点,我们将在网格项使用 grid-area 属性:
.header{
background: red;
grid-area:h;
}
.menu{
background: yellow;
grid-area: m;
}
.content{
background: green;
grid-area: c;
}
.footer{
background: gray;
grid-area: f;
}
.container {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 50px 350px 50px;
grid-template-areas:
"h h h h h h h h h h h h"
"c c c c c c c c c c m m"
"f f f f f f f f f f f f";
}
2.使用点 . 来创建空白的网格单元格
.container {
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 50px 350px 50px;
grid-template-areas:
"h h h h h h h h h h h h"
/* "m m c c c c c c c c c c" */
"c c c c c c c c c c m m"
". f f f f f f f f f f .";
}
3.真正的响应式布局
假设你想在移动设备上查看的是:标题旁边是菜单。那么你可以简单地这样做:
@media screen and (max-width:640px){
.container{
grid-template-areas:
"m m m m m h h h h h"
"c c c c c c c c c c"
"f f f f f f f f f f";
}
}
注:所有这些更改都是使用纯 CSS 完成的,不需要修改 HTML 。这被称为结构和表现分离, Grid(网格) 布局真正做到了这点。