css布局——Grid【搬运】

CSS 网格布局(Grid Layout) 是CSS中最强大的布局系统。 这是一个二维系统,这意味着它可以同时处理列和行,不像 flexbox 那样主要是一维系统。 你可以通过将CSS规则应用于父元素(成为网格容器)和该元素的子元素(网格元素),来使用网格布局。

一、 前言铺垫

1.引言

CSS网格布局(又名“网格”)是一个二维的基于网格的布局系统,其目的只在于完全改变我们设计基于网格的用户界面的方式。 CSS一直用来布局网页,但一直都不完美。 一开始我们使用table 做布局,然后转向浮动、定位以及inline-block,但所有这些方法本质上都是 Hack 的方式,并且遗漏了很多重要的功能(例如垂直居中)。 Flexbox的出现在一定程度上解决了这个问题,但是它的目的是为了更简单的一维布局,而不是复杂的二维布局(Flexbox和Grid实际上一起工作得很好)。 只要我们一直在制作网站,我们就一直在为解决布局问题不断探索, 而Grid是第一个专门为解决布局问题而生的CSS模块。

本文包括18个小节,50个实例,完整阅读需要时间20分钟以上。

2.重要术语

在深入了解网格的概念之前,理解术语是很重要的。 由于这里所涉及的术语在概念上都是相似的,如果不先记住它们在网格规范中定义的含义,则很容易将它们彼此混淆。 但是不用太担心,这些术语并不多。

Grid Container

设置了 display: gird 的元素。 这是所有grid item的直接父项。 在下面的例子中,.container就是是 grid container。

<div class="container">
  <div class="item item-1"></div>
  <div class="item item-2"></div>
  <div class="item item-3"></div>
</div> 

Grid Item

Grid 容器的孩子(直接子元素)。下面的 .item 元素就是 grid item,但 .sub-item不是。

<div class="container">
  <div class="item"></div> 
  <div class="item">
    <p class="sub-item"></p>
  </div>
  <div class="item"></div>
</div>

Grid Line

这个分界线组成网格结构。 它们既可以是垂直的(“column grid lines”),也可以是水平的(“row grid lines”),并位于行或列的任一侧。 下面例中的黄线就是一个列网格线。

Grid Track

两个相邻网格线之间的空间。 你可以把它们想象成网格的列或行。 下面是第二行网格线和第三行网格线之间的网格轨道。

Grid Cell

两个相邻的行和两个相邻的列网格线之间的空间。它是网格的一个“单元”。 下面是行网格线1和2之间以及列网格线2和3的网格单元。

Grid Area

四个网格线包围的总空间。 网格区域可以由任意数量的网格单元组成。 下面是行网格线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
  • justify-content
  • align-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

二 、实例

1 网格容器

将属性 display 值设为 grid 或 inline-grid 就创建了一个网格容器,所有容器直接子结点自动成为网格项目。

1.1 例1

grid  {
    display: grid;
}

网格项目按行排列,网格项目占用整个容器的宽度。

演示程序

1.1 例2

grid  {
    display: inline-grid;
}

网格项目按行排列,网格项目宽度由自身宽度决定。

演示程序

2 显示网格

属性grid-template-rowsgrid-template-columns用于显示定义网格,分别用于定义行轨道和列轨道。

2.1 例3

grid  {
    display: grid;
    grid-template-rows: 50px 100px;
}

属性grid-template-rows用于定义行的尺寸,即轨道尺寸。轨道尺寸可以是任何非负的长度值(px,%,em,等)

网格项目1的行高是50px,网格项目2的行高是100px。

因为只定义了两个行高,网格项目3和4的行高取决于其本身的高度。

演示程序

2.2 例4

grid  {
    display: grid;
    grid-template-columns: 90px 50px 120px;
}

类似于行的定义,属性grid-template-columns用于定义列的尺寸。

因为定义中只有三列,所以项目4,5,6排在新的一行; 并因为它们位于第1,2,3列的轨道上,所以其宽度等于定义中第1,2,3列轨道的宽度。

网格项目的第1列,第2列,第3列的宽度分别是 90px, 50px 和 120px 。

演示程序

2.3 例5

grid  {
    display: grid;
    grid-template-columns: 1fr 1fr 2fr;
}

单位fr用于表示轨道尺寸配额,表示按配额比例分配可用空间。

本例中,项目1占 1/4 宽度,项目2占 1/4 宽度,项目3占 1/2 宽度。

演示程序

2.4 例6

grid  {
    display: grid;
    grid-template-columns: 3rem 25% 1fr 2fr;
}

单位fr和其它长度单位混合使用时,fr的计算基于其它单位分配后的剩余空间。

本例中,1fr = (容器宽度 - 3rem - 容器宽度的25%) / 3

3 轨道的最小最大尺寸设置

函数minmax()用于定义轨道最小/最大边界值。

3.1 例7

grid  {
    display: grid;
    grid-template-rows:    minmax(100px, auto);
    grid-template-columns: minmax(auto, 50%) 1fr 3em;
}

函数minmax()接收两个参数:第一个参数表示最小轨道尺寸,第二个参数表示最大轨道尺寸。长度值可以是auto,表示轨道尺寸可以根据内容大小进行伸长或收缩。

本例中,第一行最小高度设置成100px,但是最大高度设置成auto,表示行高可以根据内容伸长超过100px。

本例中,第一列宽度的最大值设置成50%,表示其宽度不能超过整个容器宽度的50%。

演示程序

4 重复的网格轨道

函数repeat()用来定义重复的网格轨道,尤其适用于有多个相同项目的情况下。

4.1 例8

grid  {
    display: grid;
    grid-template-rows:    repeat(4, 100px);
    grid-template-columns: repeat(3, 1fr);
}

函数repeat()接收两个参数:第一个参数表示重复的次数,第二个参数表示轨道尺寸。

演示程序

4.2 例9

grid  {
    display: grid;
    grid-template-columns: 30px repeat(3, 1fr) 30px;
}

函数repeat()可以用在轨道定义列表当中。

本例中,第1列和第5列的宽度是30px。函数repeat()创建了中间3列,每一列宽度都是1fr

5 定义网格间隙

属性grid-column-gap 和 grid-row-gap用于定义网格间隙。

网格间隙只创建在行列之间,项目与边界之间无间隙。

5.1 例10

grid  {
    display: grid;
    grid-row-gap:    20px;
    grid-column-gap: 5rem;
}

间隙尺寸可以是任何非负的长度值(px,%,em等)。

演示程序

5.2 例11

grid  {
    display: grid;
    grid-gap: 100px 1em;
}

属性grid-gapgrid-row-gapgrid-column-gap的简写形式。

第一个值表示行间隙,第二个值表示列间隙。

5.3 例12

grid  {
    display: grid;
    grid-gap: 2rem;
}

如只有一个值,则其即表示行间隙,也表示列间隙。

6 用网格线编号定位项目

网格线本质上是用来表示网格轨道的开始和结束。

每一条网格线编号都以1开始,以1为步长向前编号,其中包括行列两组网格线。

6.1 例13

.item1 {
    grid-row-start: 2;
    grid-row-end: 3;
    grid-column-start: 2;
    grid-column-end: 3;
}

这是一个3行2列的网格,即在行上有4条网格线,在列上有3条网格线。项目1利用网格线编号定位在第2行第2列的位置上。

本例中,项目只跨越一行一列,则grid-row-endgrid-column-end的定义可以省略。

演示程序

6.2 例14

.item1 {
    grid-row:    2;
    grid-column: 3 / 4;
}

属性grid-row 是 grid-row-start 和 grid-row-end的简写形式。

属性grid-column 是 grid-column-start 和 grid-column-end的简写形式。

如果只指定一个值,它表示 grid-row/column-start

如果两个值都指定,第一个表示 grid-row/column-start ,第二个值表示grid-row/column-end。而且你必须用斜杠(/)分隔这两个值。

演示程序

6.3 例15

.item1 {
    grid-area: 2 / 2 / 3 / 3;
}

属性grid-area 是 grid-row-startgrid-column-startgrid-row-end 和 grid-column-end的简写形式。

如果四个值都指定,则第一个表示 grid-row-start, 第二个表示 grid-column-start, 第三个表示 grid-row-end ,第四个表示 grid-column-end

演示程序

7 网格项目跨越行列

网格项目默认都占用一行和一列,但可以使用前一节中定位项目的属性来指定项目跨越多行或多列

7.1 例16

.item1 {
    grid-column-start: 1;
    grid-column-end:   4;
}

通过grid-column-startgrid-column-end属性值的设置,使该网格项目跨越多列。

演示程序

7.2 例17

.item1 {
    grid-row-start: 1;
    grid-row-end:   4;
}

通过grid-row-startgrid-row-end属性值的设置,使该网格项目跨越多行。

7.3 例18

.item1 {
    grid-row:    2 / 5;
    grid-column: 2 / 4;
}

简写属性 grid-row 和 grid-column 即能用来定位项目,也能用来使项目跨越多个行列。

7.4 例19

.item1 {
    grid-row:    2 / span 3;
    grid-column: span 2;
}

关键字 span 用来指定跨越行或列的数量。

演示程序

8.1 例20

grid  {
    display: grid;
    grid-template-rows:    [row-1-start] 1fr [row-2-start] 1fr [row-2-end];
    grid-template-columns: [col-1-start] 1fr [col-2-start] 1fr [col-3-start] 1fr [col-3-end];
}

用属性grid-template-rows 和 grid-template-columns定义网格,同时定义网格线名称。

为避免混淆,网格线名称应避免使用规范中的关键字(span等)。

定义网格线名称的方法是要将其放在中括号内([name-of-line]),并要和网格轨道相对应。

8.2 例21

grid  {
    display: grid;
    grid-template-rows:    [row-start row-1-start] 1fr [row-1-end row-2-start] 1fr [row-2-end row-end];
    grid-template-columns: [col-start] 1fr [col-2-start] 1fr [col-3-start] 1fr [col-end];
}

可以给同一网格线定义多个名称,方法就是在中括号内用空格将多个名称分开。

每一个网格线名都可以被引用,以用来定位网格项目。

9 用网格线名定位项目

利用命名的网格线,可以很方便地进行项目定位。

9.1 例22

.item1 {
    grid-row-start:    row-2-start;
    grid-row-end:      row-end;
    grid-column-start: col-2-start;
    grid-column-end:   col-end;
}

引用网格线名称不用加中括号。

演示程序

9.2 例23

.item1 {
    grid-row:    row-2-start / row-end;
    grid-column: col-2-start / col-end;
}

简写属性grid-row 和 grid-column也可以利用网格线名称来定位项目。

演示程序

10 用同名网格线命名和定位项目

函数repeat()可以定义同名网格线。这节省了给每条网格都命名的时间。

10.1 例24

grid {
    display: grid;
    grid-template-rows: repeat(3, [row-start] 1fr [row-end]);
    grid-template-columns: repeat(3, [col-start] 1fr [col-end]);
}

函数repeat()可以用来定义同名网格线。 这样多个网格线拥有相同的名字。

同名网格线会被分配一个位置编号,做为其唯一标识。

10.2 例25

.item1 {
    grid-row:    row-start 2 / row-end 3;
   grid-column: col-start / col-start 3;
}

用同名网格线来定位项目时,应注意在网格线名称和编号之间有一个空格。

本例中,项目1的行定位开始于第2条名称是row-start的网格线,结束于第3条名称是row-end的网格线;列定位开始于第1条名称是col-start的网格线,结束于第3条名称是col-start的网格线。

演示程序

11 用网格区域命名和定位项目

如同网格线命名,可以用属性grid-template-areas给网格区域命名。网格区域名称可以用来定位网格项目。

11.1 例26

grid {
    display: grid;
    grid-template-areas:   "header header"
                        "content sidebar"
                        "footer footer";
    grid-template-rows:    150px 1fr 100px;
    grid-template-columns: 1fr 200px;
}

一组区域名称要放在单引号或双引号内,每一个名称之间以空格分隔。

每一组名称定义一行,每一个名称定义一列。

11.2 例27

header {
    grid-row-start: header;
    grid-row-end: header;
    grid-column-start: header;
    grid-column-end: header;
}

网格区域名称可以用在属性grid-row-startgrid-row-endgrid-column-start, 和 grid-column-end的值中,用来定位项目。

11.3 例28

footer {
    grid-row: footer;
    grid-column: footer;
}

网格区域名称也可以用于简写属性grid-row 和 grid-column的值中。

11.4 例29

aside {
    grid-area: sidebar;
}

网格区域名称也可以用于简写属性grid-area的值中。

演示程序

12 隐式网格

隐式网格用来在显式网格之外定位项目。有时在显示网格中没有足够的空间,或者是要在显示网格之外定位项目就要用到隐式网格。这时可以把这些项目放置在隐式网格中。

隐式网格可以通过属性 grid-auto-rowsgrid-auto-columns, 和 grid-auto-flow 来定义。

12.1 例30

grid {
    display : grid;
    grid-template-rows:    70px;
    grid-template-columns: repeat(2, 1fr);
    grid-auto-rows:        140px;
}

本例中,只定一个行轨道,因此项目 1 和 2 高 70px 。

第2行轨道有隐式网格自动创建并为项目 3 和 4 分配了空间。 属性grid-auto-rows 定义了隐式网格的行轨道尺寸,即项目3和4的高度是 140px 。

演示程序

12.2 grid-auto-flow

如果你存在没有显示指明放置在网格上的 grid item,则自动放置算法会自动放置这些项目。 而该属性则用于控制自动布局算法的工作方式。

  • row - 告诉自动布局算法依次填充每行,根据需要添加新行
  • column - 告诉自动布局算法依次填充每列,根据需要添加新列
  • dense - 告诉自动布局算法,如果后面出现较小的 grid item,则尝试在网格中填充空洞
.container {
  grid-auto-flow: row | column | row dense | column dense
}

需要注意的是,dense 可能导致您的 grid item 乱序。

举例, 考虑如下 HTML:

<section class="container">
  <div class="item-a">item-a</div>
  <div class="item-b">item-b</div>
  <div class="item-c">item-c</div>
  <div class="item-d">item-d</div>
  <div class="item-e">item-e</div>
</section>

你定义一个有5列和2行的网格,并将 grid-auto-flow 设置为 row(这也是默认值):

.container {
  display: grid;
  grid-template-columns: 60px 60px 60px 60px 60px;
  grid-template-rows: 30px 30px;
  grid-auto-flow: row;
}

当把 grid item 放在网格上时,你只把其中两个设置了固定的位置:

.item-a {
  grid-column: 1;
  grid-row: 1 / 3;
}
.item-e {
  grid-column: 5;
  grid-row: 1 / 3;
}

因为我们将 grid-auto-flow 设置为row,所以我们的grid就像这样。 注意观察我们没有做设置的三个项目(item-b,item-c和item-d)是如何在剩余的行水平摆放位置的:

如果我们将 grid-auto-flow 设置为 column,则 item-b,item-c 和 item-d 以列的顺序上下摆放:

.container {
  display: grid;
  grid-template-columns: 60px 60px 60px 60px 60px;
  grid-template-rows: 30px 30px;
  grid-auto-flow: column;
}

13 隐式命名的网格区域

网格线名称可以任意指定,但分配以 -start 和 -end 结尾的名字有额外的益处,这样隐式地创建了具名网格区域,该名称可以用于项目定位。

13.1 例31

grid {
    display : grid;
    grid-template-rows:    [outer-start] 1fr [inner-start] 1fr [inner-end] 1fr [outer-end];
    grid-template-columns: [outer-start] 1fr [inner-start] 1fr [inner-end] 1fr [outer-end];
}

本例中,行和列都有名为inner-start 和 inner-end的网格线,它们隐式地给网格区域分派了名称(inner)。

item1 {
    grid-area: inner;
}

这样我们就能够直接使用网格区域名来定位,而不需要再用网格线来定位项目了。

演示程序

14 隐式命名的网格线

隐式命名网格线和隐式命名的网格区域的工作原理刚好相反。

14.1 例32

grid {
    display : grid;
    grid-template-areas:   "header header"
                        "content sidebar"
                        "footer footer";
    grid-template-rows:    80px 1fr 40px;
    grid-template-columns: 1fr 200px;
}

定义网格区域时隐式的命名了网格线的名称。这些网格线的名称是基于区域名加上-start 或 -end后缀组成的。

14.2 例33

item1 {
    grid-row-start:    header-start;
    grid-row-end:      content-start;
    grid-column-start: footer-start;
    grid-column-end:   sidebar-end;
}

本例中,header是通过隐式网格线名称进行定位的。

演示程序

15 层叠网格项目

通过项目定位可以使多个项目层叠在一起,属性z-index可以改变层叠项目的层次。

15.1 例34

.item-1, .item-2 {
  grid-row-start:  1;
  grid-column-end: span 2;
}
.item-1 { grid-column-start: 1; z-index: 1; }
.item-2 { grid-column-start: 2 }

本例中,项目1 和 2 行定位开始于第1条行网格线,并跨越两列。

两个项目都是用网格线编号进行定位。项目1起始于第1条列网格线,项目2起始于第2条列网格线,这使得两个项目在第一行中间列发生层叠。

缺省情况下,项目2将层叠于项目1之上;然而,给项目1设置属性z-index: 1就使得项目1层叠于项目2之上。

演示程序

15.2 例35

.overlay {
    grid-row-start:    header-start;
    grid-row-end:      content-end;
    grid-column-start: content-start;
    grid-column-end:   sidebar-start;
    z-index: 1;
}

本例中,利用在 grid-template-areas 定义中的隐式网格线名称,定位了一个网格项目(overlay),并将层叠于上层。

演示程序

16 网格项目的对齐方式

CSS的 盒模型对齐模块 补充了CSS网格的内容,网格项目可以按行或列的轴线方向实现多种对齐方式。

属性justify-items 和 justify-self 以行轴为参照对齐项目,属性align-items 和 align-self 以列轴为参照对齐项目。

属性justify-items 和 align-items 是网格容器的属性,并支持如下这些值:

  • auto
  • normal
  • start
  • end
  • center
  • stretch
  • baseline
  • first baseline
  • last baseline

16.1 例36

.grid {
    grid-template-rows: 80px 80px;
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "content content"
                       "content content";
}
.item { grid-area: content }
.grid {
    justify-items: start
}

在行的轴线起点处对齐。

16.2 例37

grid {
    justify-items: center;
}

在行的轴线中点处对齐。

16.3 例38

grid {
    justify-items: end;
}

在行的轴线终点处对齐。

16.4 例39

grid {
    justify-items: stretch;
}

在行的轴线方向延伸并填满整个区域。stretch是缺省值。

16.9 例40

grid {
    justify-items: center;
    align-items:   center;
}

项目定位于行轴和列轴线的中间位置。

17 网格项目的对齐方式2

项目可以用属性align-self 和 justify-self定义自己的对齐方式,并支持如下这些属性值:

  • auto
  • normal
  • start
  • end
  • center
  • stretch
  • baseline
  • first baseline
  • last baseline

17.1 例41

.item1 { justify-self: start }
.item2 { justify-self: center }
.item3 { justify-self: end }

属性justify-self 在行的轴线方向定义对齐方式。

17.2 例42

.item1 { align-self: start }
.item2 { align-self: center }
.item3 { align-self: end }

属性align-self 在列的轴线方向定义对齐方式。

17.3 例43

.item1 {
    justify-self: center
    align-self:   center
}

项目1定位在行的轴线和列的轴线的中间位置。

18 网格轨道的对齐方式

在网格容器中,网格轨道延轴线方向有多种对齐方式。

属性align-content用于定义网格轨道延着行的轴线的对齐方式,而属性justify-content用于定义网格轨道沿着列的轴线的对齐方式。并分别支持如下属性:

  • normal
  • start
  • end
  • center
  • stretch
  • space-around
  • space-between
  • space-evenly
  • baseline
  • first baseline
  • last baseline

18.1 例44

.grid {
    width: 100%;
    height: 300px;
    grid-template-columns: repeat(4, 45px);
    grid-template-rows: repeat(4, 45px);
    grid-gap: 0.5em;
    justify-content: start;
}

列的轨道在行的轴线起点处对齐。start 是缺省值。

18.2 例45

.grid {
    justify-content: end;
}

列的轨道在行的轴线终点处对齐。

18.3 例46

.grid {
    justify-content: center;
}

列的轨道在行的轴线中间处对齐。

18.4 例47

.grid {
    justify-content: space-around;
}

在每一列的两侧平均分配额外空间。

18.5 例48

.grid {
    justify-content: space-evenly;
}

在列与列之间及列与边界之间平均分配额外空间。

18.6 例49

.grid {
    justify-content: space-between;
}

在列与列之间平均分配额外的空间。

18.7 例50

.grid {
    align-content: start|center|end|space-around|space-between|space-evenly;
}

与justify-content类似。

三、结束语

参考文章:

CSS网格布局(Grid)完全教程

CSS Grid 系列(上)-Grid布局完整指南

猜你喜欢

转载自blog.csdn.net/ycq521131/article/details/81836441