CSS Grid布局(又称为 “网格布局” ),是一个基于网格的二维布局系统。
一开始我们用表格(table),然后是浮动(float),再是定位(postion)和内嵌块(inline-block)来布局页面,但是所有这些方法本质上都是只是 hack 而已,并且遗漏了很多重要的功能(例如垂直居中)。Flexbox 很大程度上改善了我们的布局方式,但它只是解决了更简单的一维布局,而不是复杂的二维布局(实际上 Flexbox 和 Grid 能协同工作,而且配合得非常好)。Grid(网格) 布局是第一个专门为解决布局问题而创建的 CSS 模块。
这篇文章,我将使用 CSS Grid 进行快速布局。
HTML 结构:
<div class="container">
<div class="header">HEADER</div>
<div class="menu">MENU</div>
<div class="content">CONTENT</div>
<div class="footer">FOOTER</div>
</div>
设置基本的 CSS:
.container {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 50px 350px 50px;
grid-gap: 5px;
}
在 container 元素设置 display: grid;
,将其设置为网格容器;
使用 grid-template-columns
属性创建一个 12 列的网格,每个列都是一个单位宽度(总宽度的 1/12 ),(注:其中, repeat(12, 1fr) 意思是 12 个重复的 1fr 值。 fr 是网格容器剩余空间的等分单位。);
使用 grid-template-rows
属性创建 3 行,第一行高度是 50px ,第二行高度是 350px 和第三行高度是 50px;
使用 grid-gap
属性在网格中的网格项之间添加一个间隙;
添加 grid-template-areas
:
.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";
}
这个属性被称为网格区域,也叫模板区域。
grid-template-areas
属性背后的逻辑是你在代码中创建的网格可视化表示。正如你所看到的,它有 3 行 12 列,和我们在 grid-template-columns
和 grid-template-rows
中定义的正好呼应。
每行代表一行,用网格术语来说是 网格轨道(Grid Track) ,每个字符( h,m,c,f)代表一个网格单元格。注:其实是 网格区域(Grid Area) 名称,你可以使用任意名称。四个字母中的每一个现在都形成一个矩形 grid-area
。
你可能已经猜到,我选择了字符 h,m,c,f,是因为他们是 header, menu, content 和 footer 的首字母。 当然,我可以把它们叫做任何想要的名称,但是使用他们所描述的东西的第一个字符更加容易让人理解。
给网格项设定网格区域名称:
现在将这些字符与网格中的 网格项 建立对应的连接。在网格项使用 grid-area
属性即可:
.header {
grid-area: h;
}
.menu {
grid-area: m;
}
.content {
grid-area: c;
}
.footer {
grid-area: f;
}
以下是完整的布局效果:
尝试其他布局:
Grid(网格) 布局 的精妙之处在于我们可以很容易地对布局进行修改尝试。只需修改 grid-template-areas 属性的字符即可。举个例子,把 menu 移到左边:
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”;
我们可以使用点 . 来创建空白的网格单元格。
grid-template-areas:
“. 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 .”;
修改的布局效果看起来是这样的:
添加响应式布局:
将 Grid(网格) 布局 与 响应式布局 结合起来,简直就是一个杀手锏。因为在 Grid(网格) 布局之前,仅使用 HTML 和 CSS 实现的响应式布局不可能的做到简单而又完美。
假设你想在移动设备上查看的是:标题旁边是菜单。那么你可以简单地这样做:
@media screen and (max-width: 640px) {
.container {
grid-template-areas:
"m m m m m m h h h h h h"
"c c c c c c c c c c c c"
"f f f f f f f f f f f f";
}
}
你可以看到以下效果:
会发现,所有这些更改都是使用纯 CSS 完成的,不需要修改 HTML 。 不管 div 标签在 HTML 中是怎么样的顺序结构,我们都可以随意转换。这点与 flexbox 类似,网格项(grid items)的源顺序无关紧要。CSS 可以以任何顺序放置它们,这使得用 媒体查询(media queries)重新排列网格变得非常容易。
这被称为结构和表现分离, Grid(网格) 布局真正做到了这点,对于 CSS 来说是一个巨大的进步。它允许 HTML 成为它想要的样子: 作为内容的标记。HTML 结构不再受限于样式表现,比如不要为了实现某种布局而多次嵌套,现在这些都可以让 CSS 来完成。
最终代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>grid demo</title>
<style>
* {
padding: 0;
margin: 0;
}
.container {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 50px 350px 50px;
grid-gap: 5px;
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"
;
}
@media screen and (max-width: 640px) {
.container {
grid-template-areas:
"m m m m m m h h h h h h"
"c c c c c c c c c c c c"
"f f f f f f f f f f f f";
}
}
.header {
grid-area: h;
background: khaki;
}
.menu {
grid-area: m;
background: orchid;
}
.content {
grid-area: c;
background: goldenrod;
}
.footer {
grid-area: f;
background: lightcoral;
}
</style>
</head>
<body>
<div class="container">
<div class="header">HEADER</div>
<div class="menu">MENU</div>
<div class="content">CONTENT</div>
<div class="footer">FOOTER</div>
</div>
</body>
</html>