本文为译文,由于笔者也是最近开始尝试翻译文章,若有翻译地不合理或者不正确的地方,欢迎指出。原文地址:CSS Grid: illustrated introduction。css
我还记得第一次学习CSS知识的时候,我是如何兴奋地学习使用float和inline展现元素在想要的布局位置。我想知道若是当时有一个二维布局系统,我会做何反应。事实上,即便到如今我仍是感到兴奋,由于咱们编写CSS的方式以及咱们编写标记语言的方式改变了一切。使用CSS网格,使得咱们构建响应式的、动态的、源码顺序独立的布局比以前更加容易。html
注意,源码顺序独立只是根据字面翻译,我理解的含义是编写的html标签的顺序跟页面上展现标签的顺序无关,咱们能够经过CSS 网格样式任意修改元素在页面上的展现顺序。算法
在本文中,咱们将学习使用全部的CSS网格知识来构建简单的和一些不太容易的布局。咱们将定义一切CSS网格知识,而后接着将挖掘得更深一点,看看咱们可使用CSS网格实现什么样的布局。话虽如此,若是你已经准备好学习一种新的布局方式,吃下红色药丸,我会告诉你兔子洞到底有多深。编程
在咱们开始学习以前,我想提出一些或许你也可能有的一些顾虑,同时确保咱们熟悉CSS网格的基础知识和术语。浏览器
Q:CSS网格会替代flex-box布局吗?框架
A:固然,CSS网格不会替代flex-box,这两种布局是针对不一样的使用场景。事实上,它们还能够很好地搭配使用。咱们能够在CSS网格布局中使用flex布局,反之亦然。函数
Q:CSS网格布局和flex-box布局有什么不一样?布局
A:它们有不少不一样点,最主要的区别就是flex-box是一种一维的布局系统,而CSS网格是一种二维的布局系统。让咱们看看下图:学习
Q:为何不使用Bootstrap呢?flex
A:我认为最好的回答是引用Jen Simmons的表述:
使用CSS Grid越多,使我更加确信,在其上添加抽象层没有任何好处,CSS网格就是是嵌入浏览器的CSS布局框架。
Q:CSS 网格为用于生产环境准备好了吗?
A:这取决于你的网站,你的网站是否要兼容IE,Opera mini,Blackberry browser,Baidu mobile等浏览器?若是回答是否认,你能够直接用于生产环境。若是回答是确定,那么你能够在支持它的浏览器(不须要添加前缀的浏览器占比:91.61%)使用它经过编写@supports
CSS规则:
@supports (display: grid) {
div {
display: grid;
}
}
复制代码
基本上,一个网格布局中能够分解为两个元素:容器(grid container)和项目(grid-items)。
从图二中咱们能够看到,网格容器就是一个行和列的集合。一行就是两根连续的水平线之间的空间,一列就是两根连续的竖线之间的空间。一行被称为一个轨道(track),对于列也同样。所以网格轨道就是两根平行的网格线之间的空间。
每个轨道能够有一个或者多个网格单元。cell就是最小的、最基本的网格单元,它是四根相交的网格线之间的空间。若是咱们把多个网格单元组合起来就造成了一个网格区域,值得一提的是网格区域必须是一个矩形区域,例如咱们不能产生一个T形状的网格区域。
网格线从1开始到任何编号你能够显示或者隐式的定义,最后的网格线编号能够被设为-1,而在它以前的网格线编号为-2,依此类推,这个在稍后的例子中会很方便。在图二中列网格线的编号是从1增长6(或者是从-6到-1),行的网格线编号是从1增长到5(或者是从-5到-1)。
网格线的编号能够被显示的定义若是你在CSS样式中明确设置,它也能够被隐式地设置若是它是被浏览器动态地生成。
最后要补充地是,网格单元能够经过空格和间距分开,这些间距被称为“槽”(gutters),可是咱们通常把它们当成间距。
好了,这样咱们能够开始实现一些网格布局。首先咱们讨论网格容器可使用的全部属性,而后再介绍一下关于网格项(item)的一些属性。
在本节中,让咱们考虑以下模板:
<div class="grid-container">
<div class="grid-item">grid item 1</div>
<div class="grid-item">grid item 2</div>
<div class="grid-item">grid item 3</div>
<div class="grid-item">grid item 4</div>
<div class="grid-item">grid item 5</div>
<div class="grid-item">grid item 6</div>
<div class="grid-item">grid item 7</div>
<div class="grid-item">grid item 8</div>
<div class="grid-item">grid item 9</div>
</div>
复制代码
Display
CSS网格是使用display属性的grid
值定义的 ,所以,使用上面的模板定义网格布局,咱们应该这样作:
.grid-containter {
display: grid;
}
复制代码
咱们能够经过使用grid-template-rows
和grid-template-columns
属性定义网格的行和列:
.grid-container {
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr auto 2fr;
}
复制代码
或者咱们可使用grid-template属性首先定义grid-template-rows
而后定义grid-template-columns
(使用斜杆分隔):
.grid-container {
grid-template: 1fr auto 2fr / 1fr 1fr 1fr 1fr;
}
复制代码
顺便提一下,fr
是一个分数单位,所以1fr
就是可用空间的一个部分。
repeat
函数表示轨道(track)列表的一个重复片断,所以咱们能够获得和上面同样的模板经过以下代码:
.grid-container {
grid-template: 1fr auto 2fr / repeat(4, 1fr);
}
复制代码
阅读文档repeat 能够了解怎么使用auto-fit
和auto-fill
动态地添加轨道(track)。
minmax
函数定义了一个尺寸的范围,该范围大于或者等于最小值,小于或者等于最大值,咱们能够将该函数和repeat一块儿使用:
.grid-container {
grid-columns: repeat(3, minmax(100px, 1fr));
}
复制代码
咱们可使用row-gap
给行与行之间设置间距,一样也可使用column-gap
给列与列设置间距:
.grid-container {
row-gap: 5px;
column-gap: 10px;
}
复制代码
咱们也可使用gap
属性先定义行间距而后定义列间距:
.grid-container {
gap: 5px 10px;
}
复制代码
若是row-gap
和column-gap
值是同样的,咱们只须要指定一个值。
指定一个网格项在网格布局中的开始和结束位置,咱们基本上使用四个属性,让咱们先看下它们的定义。
属性 | 定义 |
---|---|
grid-row-start | grid-row-start属性经过提供一个行、一个span或者什么都不提供来指定网格行在网格中的开始位置(自动) |
grid-row-end | grid-row-end属性经过提供一个行、一个span或者什么都不提供来指定网格行在网格中的结束位置(自动) |
grid-column-start | grid-column-start属性经过提供一个行、一个span或者什么都不提供来指定网格列在网格中的开始位置(自动) |
grid-column-end | grid-column-end属性经过提供一个行、一个span或者什么都不提供来指定网格列在网格中的结束位置(自动) |
或者咱们也可使用这些属性的简写形式:
属性 | 定义 |
---|---|
grid-row | grid-row 属性是grid-row-start 和grid-row-end 的简写属性,用于指定网格行中网格项的大小和位置 |
grid-column | grid-column属性是grid-column-start 和grid-column-end 的简写属性,用来指定网格列中网格项的大小和位置 |
考虑一下咱们在本节开始时使用的标记,假设咱们想要第三个网格项占用四个单元格而不是一个(咱们但愿它跨越两个网格列和两个网格行),效果就像图三同样,咱们该怎么作了?
咱们能够像这样实现:
// Grid container
.grid-container {
display: grid;
gap: 10px;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 1fr);
}
// Grid item (third)
.grid-container .grid-item:nth-child(3) {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 3;
// or
grid-column: 1 / 3;
grid-row: 1 / 3;
// or
grid-column: 1 / span 2;
grid-row: 1 / span 2;
// or
grid-column: -5 / span 2; // because we have 4 columns
grid-row: -4 / span 2; // because we have 3 rows
}
复制代码
注意,第三个网格项其实就是图三中的第一个,这与CSS网格能够(第一次)拥有源码顺序独立性有关。当咱们讨论
grid-auto-flow
的时候,咱们还会讲到这个知识点。
若是你想玩它,探索不一样的解决方案,点击这里。
还有一些更高级的属性能够帮助您按照本身的须要调整模板。在这小节,咱们将学习这些属性并知道如何在CSS中使用它们。
在这个小节,咱们考虑以下模板:
<div class="grid-container">
<div class="grid-item header">Header</div>
<div class="grid-item content">Content</div>
<div class="grid-item navbar">Navbar</div>
<div class="grid-item meta">Meta</div>
<div class="grid-item footer">Footer</div>
</div>
复制代码
使用咱们前面学过的知识,咱们可使用以下的CSS样式使得它看起来像一个基本的网站布局:
.grid-container {
grid-template: repeat(6, 1fr) / repeat(12, 1fr);// rows then columns
}
.grid-container .header {
grid-column: 1 / -1;
grid-row: 1 / 2;
}
.grid-container .navbar {
grid-column: 1 / 2;
grid-row: 2 / -1;
}
.grid-container .content {
grid-column: 2 / -1;
grid-row: 2 / -2;
}
.grid-container .footer {
grid-column: 2 / -1;
grid-row: -2 / -1;
}
.grid-container .meta {
grid-column: -3 / -1;
grid-row: 2 / 4;
}
复制代码
如今假设咱们想要导航条(在右边)宽一点,目前,它跨越了一列,可是咱们想要它跨越两列。为了实现这个效果,咱们须要改变.navbar
的位置,同时也要改变.content
和.footer
的位置,由于当前.navbar
是从列1到列2,而.footer
和.content
是从列2一直到最后。
若是每次都要修改元素的位置,那就太单调了。若是有一种办法来告诉CSS网格自动为咱们去作这件事,那就太好了。固然,不止有一种方法能够实现,至少有两种方法。
第一种解决方案就是命名特定的行,而后咱们能够用它的别名而不是它的编号来引用它,让咱们尝试实现它。
.grid-container {
grid-template-rows: repeat(6, 1fr);
grid-template-columns: 1fr 1fr [content-start navbar-end] repeat(10, 1fr);
}
复制代码
在上面的代码中,咱们使用包含别名的简单方括号为第三行命名(单一的行能够有多个别名)。而后咱们修改前面提到的元素的CSS代码:
.grid-container .navbar {
grid-column: 1 / navbar-end;
grid-row: 2 / -1;
}
.grid-container .content {
grid-column: content-start / -1;
grid-row: 2 / -2;
}
.grid-container .footer {
grid-column: content-start / -1;
grid-row: -2 / -1;
}
复制代码
实现的效果像下面这样:
尝试对其它的行实现相同的效果(前面的:header-row-end / content-row-start
)能够点击下面的代码片断
第二种解决方案是使用模板区域,grid-template-areas
属性用来指定命名的网格区域。这个属性有个奇怪的CSS语法,但咱们像这样使用它:
.grid-container {
grid-template-areas:
'h h h h h h h h h h h h'
'n n c c c c c c c c c c'
'n n c c c c c c c c c c'
'n n c c c c c c c c c c'
'n n c c c c c c c c c c'
'n n f f f f f f f f f f';
}
.grid-container .navbar {
grid-area: n;
}
.grid-container .content {
grid-area: c;
}
.grid-container .footer {
grid-area: f;
}
.grid-container .header {
grid-area: h;
}
.grid-container .meta {
grid-column: -3 / -1;
grid-row: 2 / 4;
}
复制代码
咱们使用grid-template-areas
定义网格容器区域,而后使用grid-area
将网格项放置到须要的网格区域。值得注意的是,全部的区域必须是矩形。
注意,咱们没有为
.meta
元素使用grid-area
,这是由于,目前没有可使用这种方式来叠加元素的方法,至少我不知道。
你能够继续玩它,可用的代码点击这里。
考虑以下代码:
<div class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
</div>
<style> .grid-container { grid-template-columns: repeat(3, minmax(100px, 1fr)); grid-template-rows: 80px; } .grid-container .grid-item:nth-child(2) { grid-row: span 2; } .grid-container .grid-item:nth-child(3) { grid-column: span 3; } </style>
复制代码
咱们有一个三列的网格,咱们想让第二个网格项跨越两行,第三个跨越三列,结果以下图:
这看起来很糟糕,因此这里发生了什么?首先,第二个元素比一个元素稍微高了一点,由于咱们想要它高一倍,可是看起来根本不像是高了一倍的高度。一样,从3到6的网格项也没有第一个高。
这与咱们显示的设置第一行CSS样式有关:grid-template-rows: 80px
,而其它的行被隐式地建立了,所以,第二行几乎是不可见的,由于它是空的,而其它行的大小取决于它们内容所须要的。
咱们能够像下面代码这样使用grid-auto-rows属性设置隐式建立的行高度来修复这个问题:
.grid-container {
grid-template-columns: repeat(4, minmax(100px, 1fr));
grid-template-rows: 80px;
grid-auto-rows: 100px;
}
复制代码
这样看起来就像下图同样:
这样看起来好一点了,可是咱们仍然能够作得更好。注意这些空白的空间,为何咱们没有使用它们放置网格4,5,6项,为了作到这样,咱们可使用grid-auto-flow
。
grid-auto-flow
属性控制自动放置算法的工做方式,准确地指定自动放置的网格项如何流入网格,它能够有多个参数(你能够点击这里了解更多),可是在这里,咱们关心的只有一个:dense
。这个值告诉浏览器将网格项放置在任何足够大的空间:
.grid-container {
grid-auto-flow: dense; // default is row
}
复制代码
这样咱们的网格看起来就很漂亮了:
讲到这里,咱们须要处理大量的信息,可是有了这些知识,咱们涵盖了大量的CSS网格属性,所以咱们能够愉快地在应用中使用CSS网格布局。这篇文章是一系列文章中的第一篇,在下一篇中,咱们将使用网格实现三个实际的例子,所以跟上节奏。
我但愿你一如既往地从文章中学到了有用的知识,快乐编程!