V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Can I use?
http://caniuse.com/
Less
http://lesscss.org
Cool Libraries
Bootstrap from Twitter
Jetstrap
iFat3
V2EX  ›  CSS

[图片版] 学习 CSS 网格布局

  •  
  •   iFat3 · 2018-05-02 14:41:53 +08:00 · 2705 次点击
    这是一个创建于 2157 天前的主题,其中的信息可能已经有所发展或是发生改变。

    简言

    CSS 网格布局( Grid )是一套二维的页面布局系统,它的出现将完全颠覆页面布局的传统方式。传统的 CSS 页面布局 一直不够理想。包括 table 布局、浮动、定位及内联块等方式,从本质上都是 Hack 的方式,并且遗漏了一些重要的功能(比如:垂直居中)。Flexbox 的出现部分解决了上述问题,但 Flex 布局是为了解决简单的一维布局,适用于页面局部布局。而 Grid 天然就是为了解决复杂的二维布局而出现的,适用页面的整体布局。在实际工作中,Grid 和 Flexbox 不但不矛盾,而且还能很好的结合使用。做为 WEB 程序员,我们在页面布局问题上都付出过努力,也将不断探索新的方案。而 Grid 是第一个专门为布局问题而生的 CSS 模块,我们有理由对 Grid 充满期待。

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

    为了获得最佳的阅体验,可以访问如下格式的教程:

    学习 CSS 网格

    1 网格容器

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

    1.1 例 1

    grid  {
        display: grid;
    }
    

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

    网格容器演示 1

    演示程序

    1.1 例 2

    grid  {
        display: inline-grid;
    }
    

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

    网格容器演示 2

    演示程序

    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 的行高取决于其本身的高度。

    显示网格演示 1

    演示程序

    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

    演示程序

    2.3 例 5

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

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

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

    显示网格演示 3

    演示程序

    2.4 例 6

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

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

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

    显示网格演示 4

    演示程序

    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%。

    轨道的最小最大尺寸设置演示 1

    演示程序

    4 重复的网格轨道

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

    4.1 例 8

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

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

    重复的网格轨道演示 1

    演示程序

    4.2 例 9

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

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

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

    重复的网格轨道演示 2

    演示程序

    5 定义网格间隙

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

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

    5.1 例 10

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

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

    定义网格间隙演示 1

    演示程序

    5.2 例 11

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

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

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

    定义网格间隙演示 2

    演示程序

    5.3 例 12

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

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

    定义网格间隙演示 3

    演示程序

    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的定义可以省略。

    用网格线编号定位项目演示 1

    演示程序

    6.2 例 14

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

    属性grid-rowgrid-row-startgrid-row-end的简写形式。

    属性grid-columngrid-column-startgrid-column-end的简写形式。

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

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

    用网格线编号定位项目演示 2

    演示程序

    6.3 例 15

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

    属性grid-areagrid-row-start, grid-column-start, grid-row-endgrid-column-end的简写形式。

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

    用网格线编号定位项目演示 3

    演示程序

    7 网格项目跨越行列

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

    7.1 例 16

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

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

    网格项目跨越行列演示 1

    演示程序

    7.2 例 17

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

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

    网格项目跨越行列演示 2

    演示程序

    7.3 例 18

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

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

    网格项目跨越行列演示 1

    演示程序

    7.4 例 19

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

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

    网格项目跨越行列演示 1

    演示程序

    8 网格线命名

    当利用属性grid-template-rowsgrid-template-columns定义网格时,可以同时定义网格线的名称。网格线名称可以用于定位网格项目。

    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-rowsgrid-template-columns定义网格,同时定义网格线名称。

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

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

    网格线命名演示 1

    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];
    }
    

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

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

    网格线命名演示 2

    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;
    }
    

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

    用网格线名定位项目演示 1

    演示程序

    9.2 例 23

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

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

    用网格线名定位项目演示 2

    演示程序

    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()可以用来定义同名网格线。 这样多个网格线拥有相同的名字。

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

    用同名网格线命名和定位项目演示 1

    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的网格线。

    用同名网格线命名和定位项目演示 2

    演示程序

    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;
    }
    

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

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

    用网格区域命名和定位项目演示 1

    11.2 例 27

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

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

    用网格区域命名和定位项目演示 2

    11.3 例 28

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

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

    用网格区域命名和定位项目演示 3

    11.4 例 29

    aside {
        grid-area: sidebar;
    }
    

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

    用网格区域命名和定位项目演示 4

    演示程序

    12 隐式网格

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

    隐式网格可以通过属性 grid-auto-rows, grid-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。

    隐式网格演示 1

    演示程序

    12.2 例 31

    grid {
        display : grid;
        grid-auto-flow: row;
    }
    

    缺省的网格布局方向是行的方向(row)。

    隐式网格演示 2

    12.3 例 32

    grid {
        display : grid;
        grid-auto-flow: column;
    }
    

    网格的布局方向可以定义为列的方向( column )。

    隐式网格演示 3

    12.4 例 33

    grid {
        display : grid;
        grid-template-columns: 30px 60px;
        grid-auto-flow:        column;
        grid-auto-columns:     1fr;
    }
    

    本例中,我们只定义了两个列轨道的尺寸 30px 和 60px。

    隐式网格中自动创建其它列并给项目 3,4,5 分配空间;分配的空间尺寸是通过属性 grid-auto-columns定义的。

    隐式网格演示 4

    演示程序

    13 隐式命名的网格区域

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

    13.1 例 34

    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-startinner-end的网格线,它们隐式地给网格区域分派了名称(inner)。

    item1 {
        grid-area: inner;
    }
    

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

    隐式命名的网格区域演示 1

    演示程序

    14 隐式命名的网格线

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

    14.1 例 35

    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后缀组成的。

    隐式命名的网格线演示 1

    14.2 例 36

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

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

    隐式命名的网格线演示 2

    演示程序

    15 层叠网格项目

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

    15.1 例 37

    .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 之上。

    层叠网格项目演示 1

    演示程序

    15.2 例 38

    .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),并将层叠于上层。

    层叠网格项目演示 2

    演示程序

    16 网格项目的对齐方式

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

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

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

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

    16.1 例 39

    .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
    }
    

    在行的轴线起点处对齐。

     网格项目的对齐方式演示 1

    演示程序

    16.2 例 40

    grid {
        justify-items: center;
    }
    

    在行的轴线中点处对齐。

     网格项目的对齐方式演示 2

    演示程序

    16.3 例 41

    grid {
        justify-items: end;
    }
    

    在行的轴线终点处对齐。

     网格项目的对齐方式演示 3

    演示程序

    16.4 例 42

    grid {
        justify-items: stretch;
    }
    

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

     网格项目的对齐方式演示 4

    演示程序

    16.5 例 43

    grid {
        align-items: start;
    }
    

    在列的轴线起点处对齐。

     网格项目的对齐方式演示 5

    演示程序

    16.6 例 44

    grid {
        align-items: center;
    }
    

    在列的轴线中点处对齐。

     网格项目的对齐方式演示 6

    演示程序

    16.7 例 45

    grid {
        align-items: end;
    }
    

    在列的轴线终点处对齐。

     网格项目的对齐方式演示 7

    演示程序

    16.8 例 46

    grid  {
        align-items: stretch;
    }
    

    在列的轴线方向延伸并填满整个区域。

    网格项目的对齐方式演示 8

    演示程序

    16.9 例 47

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

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

    网格项目的对齐方式演示 9

    演示程序

    17 网格项目的对齐方式 2

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

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

    17.1 例 48

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

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

    网格项目的对齐方式演示 10

    演示程序

    17.2 例 49

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

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

    网格项目的对齐方式演示 11

    演示程序

    17.3 例 50

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

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

    网格项目的对齐方式演示 12

    演示程序

    结语

    本教程相对全面地介绍了网格的相关内容,但这并不是一个完整的技术文档。想更全面的学习相关内容,推荐访问 Mozilla 开发者网络W3C 的网格文档。

    由于能力有限,翻译中难免错误较多,还请大家多多谅解!

    十分感谢原文作者Jonathan Suh在本文排版设计,示例制作,文字编辑等方面卓越的工作。

    为了获得最佳的阅体验,请访问如下排版的教程:

    学习 CSS 网格

    英文原版

    1 条回复    2018-05-02 14:44:36 +08:00
    iFat3
        1
    iFat3  
    OP
       2018-05-02 14:44:36 +08:00
    因为文章超过了 20000 字符,请到原文查看第 18 节的内容。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3594 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 04:44 · PVG 12:44 · LAX 21:44 · JFK 00:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.