图解CSS网格

写在前面的话

本文为译文,由于笔者也是最近开始尝试翻译文章,若有翻译地不合理或者不正确的地方,欢迎指出。原文地址:CSS Grid: illustrated introductioncss

正文开始

我还记得第一次学习CSS知识的时候,我是如何兴奋地学习使用float和inline展现元素在想要的布局位置。我想知道若是当时有一个二维布局系统,我会做何反应。事实上,即便到如今我仍是感到兴奋,由于咱们编写CSS的方式以及咱们编写标记语言的方式改变了一切。使用CSS网格,使得咱们构建响应式的、动态的、源码顺序独立的布局比以前更加容易。html

注意,源码顺序独立只是根据字面翻译,我理解的含义是编写的html标签的顺序跟页面上展现标签的顺序无关,咱们能够经过CSS 网格样式任意修改元素在页面上的展现顺序。算法

在本文中,咱们将学习使用全部的CSS网格知识来构建简单的和一些不太容易的布局。咱们将定义一切CSS网格知识,而后接着将挖掘得更深一点,看看咱们可使用CSS网格实现什么样的布局。话虽如此,若是你已经准备好学习一种新的布局方式,吃下红色药丸,我会告诉你兔子洞到底有多深。编程

matrix red pill choice

1.在咱们开始以前

在咱们开始学习以前,我想提出一些或许你也可能有的一些顾虑,同时确保咱们熟悉CSS网格的基础知识和术语。浏览器

Q & A

Q:CSS网格会替代flex-box布局吗?框架

A:固然,CSS网格不会替代flex-box,这两种布局是针对不一样的使用场景。事实上,它们还能够很好地搭配使用。咱们能够在CSS网格布局中使用flex布局,反之亦然。函数

Q:CSS网格布局和flex-box布局有什么不一样?布局

A:它们有不少不一样点,最主要的区别就是flex-box是一种一维的布局系统,而CSS网格是一种二维的布局系统。让咱们看看下图:学习

grid image

图一

Q:为何不使用Bootstrap呢?flex

A:我认为最好的回答是引用Jen Simmons的表述:

使用CSS Grid越多,使我更加确信,在其上添加抽象层没有任何好处,CSS网格就是是嵌入浏览器的CSS布局框架。

Q:CSS 网格为用于生产环境准备好了吗?

A:这取决于你的网站,你的网站是否要兼容IE,Opera mini,Blackberry browser,Baidu mobile等浏览器?若是回答是否认,你能够直接用于生产环境。若是回答是确定,那么你能够在支持它的浏览器(不须要添加前缀的浏览器占比:91.61%)使用它经过编写@supportsCSS规则:

@supports (display: grid) {
  div {
    display: grid;
  }
}
复制代码

基础知识

基本上,一个网格布局中能够分解为两个元素:容器(grid container)和项目(grid-items)。

grid image

图二

从图二中咱们能够看到,网格容器就是一个行和列的集合。一行就是两根连续的水平线之间的空间,一列就是两根连续的竖线之间的空间。一行被称为一个轨道(track),对于列也同样。所以网格轨道就是两根平行的网格线之间的空间。

每个轨道能够有一个或者多个网格单元。cell就是最小的、最基本的网格单元,它是四根相交的网格线之间的空间。若是咱们把多个网格单元组合起来就造成了一个网格区域,值得一提的是网格区域必须是一个矩形区域,例如咱们不能产生一个T形状的网格区域。

网格线从1开始到任何编号你能够显示或者隐式的定义,最后的网格线编号能够被设为-1,而在它以前的网格线编号为-2,依此类推,这个在稍后的例子中会很方便。在图二中列网格线的编号是从1增长6(或者是从-6到-1),行的网格线编号是从1增长到5(或者是从-5到-1)。

网格线的编号能够被显示的定义若是你在CSS样式中明确设置,它也能够被隐式地设置若是它是被浏览器动态地生成。

最后要补充地是,网格单元能够经过空格和间距分开,这些间距被称为“槽”(gutters),可是咱们通常把它们当成间距。

2.CSS网格的基本属性

好了,这样咱们能够开始实现一些网格布局。首先咱们讨论网格容器可使用的全部属性,而后再介绍一下关于网格项(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-rowsgrid-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 function

repeat函数表示轨道(track)列表的一个重复片断,所以咱们能够获得和上面同样的模板经过以下代码:

.grid-container {
  grid-template:  1fr auto 2fr / repeat(4, 1fr);
}
复制代码

阅读文档repeat 能够了解怎么使用auto-fitauto-fill动态地添加轨道(track)。

Minmax function

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-gapcolumn-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-startgrid-row-end的简写属性,用于指定网格行中网格项的大小和位置
grid-column grid-column属性是grid-column-startgrid-column-end的简写属性,用来指定网格列中网格项的大小和位置

基本模板间距

考虑一下咱们在本节开始时使用的标记,假设咱们想要第三个网格项占用四个单元格而不是一个(咱们但愿它跨越两个网格列和两个网格行),效果就像图三同样,咱们该怎么作了?

template spacing

图三

咱们能够像这样实现:

// 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的时候,咱们还会讲到这个知识点。

若是你想玩它,探索不一样的解决方案,点击这里

3.高级模板

还有一些更高级的属性能够帮助您按照本身的须要调整模板。在这小节,咱们将学习这些属性并知道如何在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;
}
复制代码

basic layout

图四

如今假设咱们想要导航条(在右边)宽一点,目前,它跨越了一列,可是咱们想要它跨越两列。为了实现这个效果,咱们须要改变.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;
}
复制代码

实现的效果像下面这样:

extended navbar

图五

尝试对其它的行实现相同的效果(前面的: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,这是由于,目前没有可使用这种方式来叠加元素的方法,至少我不知道。

你能够继续玩它,可用的代码点击这里

4.隐式行和网格流

考虑以下代码:

<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>
复制代码

咱们有一个三列的网格,咱们想让第二个网格项跨越两行,第三个跨越三列,结果以下图:

bad grid

图六

这看起来很糟糕,因此这里发生了什么?首先,第二个元素比一个元素稍微高了一点,由于咱们想要它高一倍,可是看起来根本不像是高了一倍的高度。一样,从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; 
} 
复制代码

这样看起来就像下图同样:

better grid, but still

图七

这样看起来好一点了,可是咱们仍然能够作得更好。注意这些空白的空间,为何咱们没有使用它们放置网格4,5,6项,为了作到这样,咱们可使用grid-auto-flow

网格流

grid-auto-flow属性控制自动放置算法的工做方式,准确地指定自动放置的网格项如何流入网格,它能够有多个参数(你能够点击这里了解更多),可是在这里,咱们关心的只有一个:dense。这个值告诉浏览器将网格项放置在任何足够大的空间:

.grid-container {
  grid-auto-flow: dense; // default is row
}
复制代码

这样咱们的网格看起来就很漂亮了:

good grid

图八

结论

讲到这里,咱们须要处理大量的信息,可是有了这些知识,咱们涵盖了大量的CSS网格属性,所以咱们能够愉快地在应用中使用CSS网格布局。这篇文章是一系列文章中的第一篇,在下一篇中,咱们将使用网格实现三个实际的例子,所以跟上节奏。

我但愿你一如既往地从文章中学到了有用的知识,快乐编程!

相关文章
相关标签/搜索