网格布局 ——(语法篇)

这是HTML&CSS重点知识点合集第四篇,内容稍微有点多。其他文章见文末。css

1、网格布局(Grid)

前面咱们讲了 伸缩盒。咱们讲到,伸缩盒是传统盒模型布局的一种代替,而且伸缩容器以及flex item的属性足以应付咱们经常使用的各类布局模式,那为何还会出现Grid网格布局呢?html

可能你已经知道了,以往任何布局方式几乎都是一维布局,而Grid最大的特点就是采用了二维布局。固然,Grid的出现并非用来替代flex-layout,而是对它的补充。前者擅长一维然后者擅长二维,它们须要各司其职。前端

2、浏览器兼容

咱们来看看它的兼容性吧。从2017年3月份开始,Grid开始获得部分的浏览器的支持。css3

gridBrowserSupport

3、Grid和table

你可能会有疑问,Grid不就是设置行和列嘛?但是这些table不是均可以作嘛?那为啥还要有Grid?git

从效果上来看,Grid布局和table同样都是把一部分区域经过行和列来划分红一小块一小块方格。可是实际上它们是有很大区别的: 1.首先,它们的本质区别在于Grid是用纯CSS实现的布局方式。而table布局依赖HTML标签,它有固定的结构。Grid能够直接使用 grid-template-columnsgrid-template-rows 属性来设置容器的行和列的长度。例如:github

.container {
  display: grid;
  grid-template-columns: 50px 50px 50px;
  grid-template-rows: 50px 50px 50px;
}
复制代码

当咱们对一个容器设置上述样式,就会生成一个三行三列且每一小格长宽均为50px。点击这里 本身实践一下!浏览器

grid exp

2.其次,基于table固定标签的结构,它的布局就很不自由。可是Grid不一样,使用它来对二维布局能够利用几行代码轻松实现,灵活性很高。网络

4、Grid布局语法

在具体讲Grid布局以前,咱们先来认识几个术语。ide

第1、和伸缩盒同样,网格布局中也有容器这个概念。网格容器(Grid container),为其内容创建新的网格格式化上下文,容器外元素和容器内元素互不干扰。好比上图中盛装数字块的最外容器。函数

第2、网格线(Grid line),顾名思义,容器的水平垂直分割线。它构建出网格轨道、网格单元和网格区域。网格线是有数字索引的,能够自定义名称。

第3、网格轨道(Grid track),网格内容块之间水平或垂直的空间。

第4、网格单元格(Grid cell),网格内容的单元区块,是能够放置内容的最小区块。好比上图中的某一个数字块。

第5、网格区域(Grid area),以网格线为界划定区域。

(1). 网格容器

网格容器全部的属性:

  1. display
  2. grid-template-columns
  3. grid-template-rows
  4. grid-template-areas
  5. grid-template
  6. grid-column-gap
  7. grid-row-gap
  8. grid-gap
  9. justify-items
  10. align-items
  11. place-items
  12. justify-content
  13. align-content
  14. place-content
  15. grid-auto-columns
  16. grid-auto-rows
  17. grid-auto-flow
  18. grid

和伸缩盒不同,在网格布局是一个二维布局,有着行和列的概念,因此咱们接下来说的容器属性是:如何定义网格容器以及如何定义网格的行数、列数以及网格的大小(长宽)。

1. display

.container {
  display: grid | inline-grid;
}
复制代码

2. grid-template-columnsgrid-template-rows

就如上面例子中同样,它们用来定义网格的行数、列数、网格大小。假设咱们须要定义一个四行四列的容器能够这样写:grid-template-columns: 50px 50px 50px 50px; grid-template-rows: 50px 50px 50px 50px;

固然,属性值除了可使用 px 做为单位还可使用 em% 来做为单位。在CSS3规范中,咱们看到这样一段话:

A flexible length or is a dimension with the fr unit, which represents a fraction of the leftover space in the grid container. Tracks sized with fr units are called flexible tracks as they flex in response to leftover space similar to how flex items fill space in a flex container.

翻译过来就是说 fr 这个单位表示的是网格容器中剩余空间的一部分。大小为 fr 单位的‘轨道’称为弹性‘轨道’,它们会响应式的填充剩余的内容,和伸缩盒中的flex item会自动填充剩余空间很类似。

假设设置一个三行四列的列表,但愿最后一列自适应容器宽度就能够这样设置:

.container {
  display: grid;
  grid-template-columns: 50px 50px 50px 1fr;
  grid-template-rows: 50px 50px 50px;
}
复制代码

三行四列,最后一列自适

那若是但愿第一列长度固定然后三列中第一列占剩余长度的四分之一,第二列占二分之一最后一列占四分之一应该该怎么写呢?

.container {
  display: grid;
  grid-template-columns: 50px 1fr 2fr 1fr;
  grid-template-rows: 50px 50px 50px;
}
复制代码

fr用作分数

怎么样?神奇吧?

对于这两个属性,CSS3还提供了一个函数:repeat()。它的做用相信你一看就知道了:

.container {
  display: grid;
  grid-template-columns: 50px 1fr 2fr 1fr;
  grid-template-rows: repeat(3, 50px);
}
复制代码

3. grid-template-areas

.container {
  grid-template-areas: "<grid-area-name> | . | none | ..." "...";
}
复制代码

它用来定义网格区域,使用 grid-area 调用声明好的网格区域名称用来放置对应的网格项目。

举个栗子:

.item-a {
  grid-area: header;
}
.item-b {
  grid-area: main;
}
.item-c {
  grid-area: sidebar;
}
.item-d {
  grid-area: footer;
}

.container {
  display: grid;
  grid-template-columns: 50px 50px 50px 50px;
  grid-template-rows: auto;
  grid-template-areas: 
    "header header header header"
    "main main . sidebar"
    "footer footer footer footer";
}
复制代码

咱们经过Grid item的属性 grid-area(后面会讲到)来为item设置相应的名称,而后再利用容器属性 grid-template-areas经过设置的名称对整个容器布局。下面就是布局的效果:

grid-area

4. grid-template

这是属性 grid-template-rowsgrid-template-columnsgrid-template-areas 三个属性的简写。

.container {
  grid-template: none | <grid-template-rows> / <grid-template-columns>;
}
复制代码

当仅仅设置 grid-template-rowsgrid-template-columns 时,grid-template-areas 自动为 none。中间使用符号 / 隔开。好比前面一个例子就能够写成这样:

.container {
  display: grid;
  grid-template: repeat(3, 50px) / 50px 1fr 2fr 1fr;
}
复制代码

grid-template 不会隐式的设置 grid-auto-columnsgrid-auto-rowsgrid-auto-flow,因此推荐使用 grid 属性来代替。

5. grid-row-gapgrid-column-gap

定义网格之间的间距(不包括grid item到容器边缘的间距)

6. justify-items

.container {
  justify-items: start | end | center | stretch; /* 默认值为stretch */
}
复制代码

定义Grid item的内容在水平方向上的对齐方式(其值指的是在单元格内的表现)。好比:

.container {
  justify-items: start;
}
复制代码

justify-items-start

.container {
  justify-items: center;
}
复制代码

justify-items-center

和伸缩容器的 align-items 同样,它也能在子项目中使用属性 justify-self 进行覆盖。

7. align-items

.container {
  align-items: start | end | center | stretch; 
}
复制代码

justify-items 差很少,只不过这个属性做用的是另外一个轴方向。

.container {
  align-items: start;
}
复制代码

align-items-start

一样的,这个属性值也能够利用子项目的属性 align-self 进行覆盖。

8. place-items
是属性 align-items 和属性 justify-items 的简写。中间使用 / 进行分隔。若只有一个值,那么将同时设置两个相同的值。

注:除了Edge,全部主流浏览器均支持该属性。

9. justify-content
有些时候,当咱们对单元格的长设置了固定值,这时就有可能致使全部网格的长加起来不能撑满整个网格容器。好比下面这样:

justify-content-start

因此,justify-content 属性就运用而生。它主要就是设置容器中内容的排布方式的。

.container {
  justify-content: start | end | center | stretch | space-around | space-between | space-evenly; 
}
复制代码

栗子以下:

.container {
  justify-content: space-around;
}
复制代码

justify content space-around

10. align-content
和上一个属性相呼应,若是咱们对每一个单元格的高设置固定值,这是就有可能致使全部单元格的高加起来没有填满整个容器。

.container {
  align-content: start | end | center | stretch | space-around | space-between | space-evenly;
}
复制代码

align-content-start

11. place-content
前两个属性的简写形式,若是只设置一个值,则表示设置相同的值。

除Edge外,全部主流浏览器都支持这个属性。

12. grid-auto-columnsgrid-auto-rows
设置隐式网格轨道的大小。

.container {
  grid-auto-columns: <track-size> ...;
  grid-auto-rows: <track-size> ...;
  /* <track-size> 长度,能够是前面提到的任何表示形式 */
}
复制代码

其实这个属性就是设置以后有可能动态添加进来的item的长度和高度。来看下面一个栗子: 首先,咱们设置好高宽:

.container {
  grid-template-columns: 60px 60px;
  grid-template-rows: 90px 90px;
}
复制代码

设置高宽高宽

如今咱们来对Grid item设置一下它的位置(这两个属性接下来会讲到,用来设置item的位置,其中/两侧的值分别是网格轨道的起始位置和终点位置):

.item-a {
  grid-column: 1 / 2;
  grid-row: 2 / 3;
}
.item-b {
  grid-column: 5 / 6;
  grid-row: 2 / 3;
}
复制代码

设置item位置

在这里咱们设置了一个 item-b,而且容易看出,它在原先定义的网格中并不存在,因而就有了上图。看到,第3、四列的长度为0,且 item-b的这一列的长度也为没设置(默认值为 auto,和前面已经定义的长度同样)。

如何解决第3、四列的长度问题呢?这里咱们就能够利用属性 grid-auto-columns 来动态的设置后添加进来item的长度。

.container {
  grid-auto-columns: 60px;
}
复制代码

自动设置长度

13. grid-auto-flow

.container {
  grid-auto-flow: row | column | row dense | column dense;
}
复制代码

它定义了默认“流”方向,它的动做和flexbox里的 flex-direction 有些类似。

14. grid
它是属性 grid-template-rowsgrid-template-columnsgrid-template-areasgrid-auto-rowsgrid-auto-columns 以及grid-auto-flow 的缩写。

.container {
  grid: none | <grid-template> | <grid-template-rows> / [auto-flow && dense?] <grid-auto-columns>? | [auto-flow && dense?] <grid-auto-rows>? / <grid-template-columns>;
}
复制代码

举个栗子就明白啦:

.container {
  grid: 100px 300px / 3fr 1fr;
}

/* 等同于下面: */
.container {
  grid-template-rows: 100px 300px;
  grid-template-columns: 3fr 1fr;
}
复制代码

再好比:

.container {
  grid: auto-flow / 200px 1fr;
}

/* 等同于下面: */
.container {
  grid-auto-flow: row;
  grid-template-columns: 200px 1fr;
}

.container {
  grid: auto-flow dense 100px / 1fr 2fr;
}

/* 等同于 */
.container {
  grid-auto-flow: row dense;
  grid-auto-rows: 100px;
  grid-template-columns: 1fr 2fr;
}
复制代码

(2). 网格项目

全部Grid item属性:

  1. grid-column-start
  2. grid-column-end
  3. grid-row-start
  4. grid-row-end
  5. grid-column
  6. grid-row
  7. grid-area
  8. justify-self
  9. align-self
  10. place-self

1. grid-column-startgrid-column-endgrid-row-startgrid-row-end
这四个属性是用来定义item的四周位置的。

.item {
  grid-column-start: <line> | <number> | <name> | span <number> | span <name> | auto;
  grid-column-end: <line> | <number> | <name> | span <number> | span <name> | auto;
  grid-row-start: <line> | <number> | <name> | span <number> | span <name> | auto;
  grid-row-end: <line> | <number> | <name> | span <number> | span <name> | auto;
}
复制代码

其中 <line> 的值能够是一个数字,表示第几根网格线,也能够是已经定义过的网格线名称。

举个栗子:

.item-a {
  grid-column-start: 2;
  grid-column-end: five;
  grid-row-start: row1-start;
  grid-row-end: 3;
}
复制代码

grid-columns-start | grid-row-start1

再好比:

.item-b {
  grid-column-start: 1;
  grid-column-end: span col4-start;
  grid-row-start: 2;
  grid-row-end: span 2;
}
复制代码

grid-columns-start | grid-row-start2

grid-column-end 或者 grid-row-end 没有被设置,则默认的跨越步长为1。Grid item有时候可能会相互重叠,这时候可使用 z-index 控制其层叠顺序。

2. grid-columngrid-row
前者是属性 grid-column-startgrid-column-end 的简写,后者是属性 grid-row-startgrid-row-end 的简写。

.item {
  grid-column: <start-line> / <end-line> | <start-line> / span <value>;
  grid-row: <start-line> / <end-line> | <start-line> / span <value>;
}
复制代码

例如:

.item-c {
  grid-column: 3 / span 2;
  grid-row: third-line / 4;
}
复制代码

grid-column grid-row

3. grid-area
这个属性咱们前面提到过,它能够用来定义Grid item的名称,用来给属性 grid-template-areas 设置布局。固然,它也能够看成属性 grid-row-startgrid-column-startgrid-row-endgrid-column-end 的简写。

.item {
  grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;
}
复制代码

关于 <name> 的栗子上面已经有了,这里再也不赘述。下面举第二个值得栗子:

.item-d {
  grid-area: 1 / col4-start / last-line / 6;
}
复制代码

grid-area

4. justify-selfalign-self
前面也提到啦,这两个属性都是子元素对父元素设置的 justify-itemsalign-items 进行覆盖。这里就再也不举栗子惹~

5. place-self
这个属性仍是比较厉(sao)害(qi)的~ 看用法:

.item-a {
  place-self: auto | <align-self> / <justify-self>;
}
复制代码

栗子:

.item-a {
  place-self: center;
}
复制代码

place-self center

.item-a {
  place-self: center stretch;
}
复制代码

place-self center stretch

最后,Grid item对属性 floatdisplay: inline-blockdisplay: table-cellvertical-aligncolumn-* 失效。

(3). 网格布局带来的函数和关键字

  • 当咱们设置长度时,咱们可使用像 px、res 、%,这些咱们以往使用的单位。咱们还可使用关键字:min-contentmax-contentauto,固然,可能最有用的仍是 fr
  • 咱们也能够经过函数 minmax() 来设置一个大小的区间段。
  • repeat(),前面已经有讲过,这里再也不赘述。

5、网格布局中的动画

根据CSS网格布局模型Level 1,有5个网格动画属性,分别是: grid-gapgrid-row-gapgrid-column-gapgrid-template-columnsgrid-template-rows

我看能够利用 @keyframes 规则,经过改变这五个属性大小达到想要的动画效果。

这里有个使用属性 transition 来实现动画的栗子:动画demo

6、伸缩盒布局和网格布局带来的思考

(1). 为何网格布局容器中有属性 justify-items 而伸缩容器没有属性 justify-items

首先,咱们来对比一下伸缩容器的 justify-content 和网格容器的 justify-content:

flexbox justify-content space-around

Grid justify-content space-around

容易看出,在伸缩容器中,每个item都是一个排列单元,而在网格容器中,每一列是一个排列单元。

如今咱们再来看看网格容器的属性:justify-items

Grid justify-items start

它的做用是在水平方向设置item内容的对齐方式。若是设置为 start,则表示全部item的内容靠近左网格线。若是设置为 center,则表示将内容在水平方向居中显示。在网格这个二维空间中,显然它是很是有用的属性。而若是咱们也为伸缩布局设置这个属性,很显然和它的属性 justify-content 的做用发生的重叠,且效果没有前者好。所以,在伸缩容器中定义 justify-items 是没有必要的。

(2). 为何最好不要使用flex布局做为整个页面的布局?

当咱们有大量的内容绘制到页面上、或者内容更改的,在2g或者网络加载不稳定的时候,页面是不稳定的。网格布局会以流的形式被获取到,且能使咱们在页面所有加载出来以前就看到内容,而flex布局因为其相对布局的特征会致使布局的重排。

固然并非说网格布局就必定不会引起重排,它是有前提的:网格的划分是预先肯定的,好比根据视窗高度来肯定。

假如内容是根据内容弹性改变的,那么也没法避免发生重排。

ps: 最后的最后,终于整理完啦,满满的收获呀。固然啦,但愿你能有所收获~
这里给你们推荐一个有趣的Grid游戏吧:grid garden,还蛮有意思的,用来入门简直不要太好~


这是HTML&CSS重点知识点合集的其中一篇,合集其它文章:
1.语义化HTML的重要性
2.传说中的BFC
3.CSS布局神器——伸缩盒(语法篇)


参考文章:
1.将来布局之星Grid-2017-09-24 by 考拉海购前端团队
2.CSS Grid 网格布局教程-2019-03-25 by 阮一峰

推荐阅读: 1.A Complete Gide to Grid-2019-9-13 by Chris

有问题?发送 issues 给我~

相关文章
相关标签/搜索