一篇文章,让你搞懂Grid布局🌟

2,134 阅读18分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

一、认识Grid布局

Flex布局是一个一维的局部方案,CSS为了进一步增强自己的布局能力,提供了Grid布局:

  • 它是一种基于二维的布局系统
  • 更加强大,同时也更加复杂
  • 但是目前使用最多的还是Flex布局,因为Grid布局兼容性比Flex布局差一些

二、相关概念

  • Grid Container:元素设置display为grid / inline-grid的盒子
  • Grid Item:grid container的直接子项(注意必须是直接子代,孙子级及其他级别子代不算)
  • Grid Cell:单元格,指的是网格布局中形成的一个个的小格子
  • Grid Line:构成网络结构的分割线,它们可以是垂直的(“列网格线”:Column Line)或水平的(“行网格线”:Row Line)
  • Grid Track:相邻网格线中间的空间,可以看成是网格的行或者列
  • Grid Area:单元格是可以进行合并的,合并的单元格组成一个区域,区域由四条网格线包围的总空间(一个网络区域可以由任意数量的单元格构成)
  • Gap:单元格与单元格之间的间隙

三、Grid容器与Grid子项相关属性

3-1、Grid容器相关属性

3-2、Grid子项相关属性

四、定义网格

使用grid-template-rowsgrid-template-columns属性去定义网格,这两个属性是基于网格行和列的维度,去定义网格线的名称和网格轨道的尺寸大小。

4-1、基本介绍

比如,定义一个3行3列的网格:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main{
        width:300px;
        height:300px;
        background:skyblue;
        display: grid;
        grid-template-columns: 100px 100px 100px;
        grid-template-rows: 100px 100px 100px;
      }
      .main div{
        background:pink;
      }
    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
      <div>7</div>
      <div>8</div>
      <div>9</div>
    </div>
  </body>
</html>

  • grid-template-columns用来定义每一列的宽度,这里每一列的宽度分别是100px
  • grid-template-rows用来定义每一行的宽度,这里每一行的宽度分别是100px

当打开调试工具将鼠标移入可以发现此时grid容器中有3行3列的单元格:

那么如果每一行的宽度与每一列的宽度相加分别小于grid 容器的高度、宽度呢?

.main{
  width:300px;
  height:300px;
  background:skyblue;
  display: grid;
  grid-template-columns: 50px 50px 50px;
  grid-template-rows: 50px 50px 50px;
}

  • 可见,此时网格将默认位于grid容器的左上方

定义每一行/列的宽度除了使用像素外,也可以使用百分比auto

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main{
        width:300px;
        height:300px;
        background:skyblue;
        display: grid;
        grid-template-columns: 50px 20% auto;
        grid-template-rows: 100px 100px 100px;
      }
      .main div{
        background:pink;
      }
    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
      <div>7</div>
      <div>8</div>
      <div>9</div>
    </div>
  </body>
</html>

  • 此时每一行的第二个单元格的宽度为300 * 0.2 = 60px , 第三个单元格宽度为300 - 150 - 60 = 190px

4-2、认识fr

使用fr单位可以成比例的分配行/列的宽度,比如:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main{
        width:300px;
        height:300px;
        background:skyblue;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr;
      }
      .main div{
        background:pink;
      }
    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
    </div>
  </body>
</html>
  • 以上可以看作将grid容器按照比例分为2行3列,那么每一个单元格的宽度为300 / 3 = 100px , 每一个单元格的高度为 300 / 2 = 150px

也可以将某一行/列扩大所占比例:

.main{
  width:300px;
  height:300px;
  background:skyblue;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 2fr 1fr;
}
  • 此时,第一行高度将是第二行的2倍,所以第一行高度为200px,第二行高度为100px

当行/列所占的比例相加小于1时将不会占满grid容器的高度/宽度:

.main{
  width:300px;
  height:300px;
  background:skyblue;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 0.3fr 0.2fr;
}
  • 此时第一行的高度将是:300 * 0.3 = 90px 、第二行高度将是300 * 0.2 = 60px

也可以将某一行/列宽度固定,其余行/列按比例分配:

.main{
  width:300px;
  height:300px;
  background:skyblue;
  display: grid;
  grid-template-columns: 200px 1fr 1fr;
  grid-template-rows: 100px 1fr;
}
  • 此时第一列单元格宽度为200px,其余两列单元格平分剩余的100px宽度,所以分别也是50px
  • 此时第一行的单元格高度为100px,第二行单元格高度为300-100 = 200px

五、合并单元格及网格命名

网格布局可以做几行*几列的布局,同时也可以进行合并单元格的操作,此时用到的是grid-template-areas属性,此属性使用命名方式定义网格区域,需配合grid-area属性进行使用。

5-1、基本使用方法

比如,现在要对3行3列的网格布局进行合并单元格的操作:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
      }
      .main div {
        background: pink;
      }
    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </div>
  </body>
</html>

此时grid子项是没有占满grid容器的,如果希望第一个子项所占区域为2行2列,第二个子项所占区域为两行,第三个子项占满第三行如何进行设置呢?

  • 此时要通过为grid容器设置grid-template-areas属性描述各个单元格区域的分配情况
  • 然后为每个子项设置grid-area属性去指定所分配的区域即可
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
        grid-template-areas: 
          "a1 a1 a2"
          "a1 a1 a2"
          "a3 a3 a3";
      }
      .main div {
        background: pink;
        border: 1px solid #ccc;
        box-sizing: border-box;
      }
      .main div:nth-of-type(1) {
        grid-area: a1;
      }
      .main div:nth-of-type(2) {
        grid-area: a2;
      }
      .main div:nth-of-type(3) {
        grid-area: a3;
      }

    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </div>
  </body>
</html>

5-2、相关特性

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
        grid-template-areas: 
          "a1 a2 a3";
      }
      .main div {
        background: pink;
        border: 1px solid #ccc;
        box-sizing: border-box;
      }
      .main div:nth-of-type(1) {
        grid-area: a3;
      }

    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </div>
  </body>
</html>

  • 比如现在通过单元格区域命名指定了三个区域后,将第一个子项指定给区域3,则其余子项将按照顺序依次填充给另外两个区域,并不会被挤到下一行来
  • 从此看出,可以利用此特性来实现各种组合方式

六、grid-template

grid-template是grid-template-rowsgrid-template-columnsgrid-template-areas的简写

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main{
        width:300px;
        height:300px;
        background:skyblue;
        display: grid;
        /* grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
        grid-template-areas: 
        "a1 a1 a2"
        "a1 a1 a2"
        "a3 a3 a3"; */
        grid-template: 
          "a1 a1 a2" 1fr
          "a1 a1 a2" 1fr 
          "a3 a3 a3" 1fr
          / 1fr 1fr 1fr;
      }
      .main div{
        background:pink;
        border:1px solid #ccc;
        box-sizing: border-box;
      }
      .main div:nth-of-type(1){
        grid-area: a1;
      }
      .main div:nth-of-type(2){
        grid-area: a2;
      }
      .main div:nth-of-type(3){
        grid-area: a3;
      }
    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </div>
  </body>
</html>
  • 区域命名后面跟上空格再指定行的大小
  • 斜杠后面跟的是每一列的宽度

七、网格间隙

  • grid-row-gap:用来定义每行之间的间隙大小
  • grid-column-gap:用来定义每列之间的间隙大小
  • grid-gap:grid-row-gap与grid-column-gap的简写

也可分别写成:row-gap、column-gap、gap(由于最初gap是用于网格布局,但后来也可以用于其他布局中如flex布局,所以更推荐将"grid-"前缀去掉)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>

      .main{
        width:300px;
        height:300px;
        background:skyblue;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
        grid-template-areas: 
          "a1 a1 a2"
          "a1 a1 a2"
          "a3 a3 a3";
        /* grid-row-gap: 20px;
        grid-column-gap: 30px; */
        row-gap: 20px;
        column-gap: 30px;
      }
      .main div{
        background:pink;
        border:1px black solid;
        box-sizing: border-box;
      }
      .main div:nth-of-type(1){
        grid-area: a1;
      }
      .main div:nth-of-type(2){
        grid-area: a2;
      }
      .main div:nth-of-type(3){
        grid-area: a3;
      }
    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </div>
  </body>
</html>

  • 也可以通过grid-gap / gap复合样式指定行和列的大小:
    • grid-gap: [row-gap] [column-gap]
    • gap: [row-gap] [column-gap] (更推荐此写法)
.main{
  width:300px;
  height:300px;
  background:skyblue;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  grid-template-areas: 
    "a1 a1 a2"
    "a1 a1 a2"
    "a3 a3 a3";
  /* grid-row-gap: 20px;
  grid-column-gap: 30px; */
  /* row-gap: 20px;
  column-gap: 30px; */
  /* grid-gap: 20px 30px; */
  gap:20px 30px;
}
  • row-gap、column-gap、gap也同样适用于flex布局
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>

      .main2{
        width:300px;
        background:skyblue;
        display: flex;
        flex-wrap: wrap;
        row-gap: 20px;
        column-gap: 30px;
      }
      .main2 div{
        width:100px;
        height:100px;
        background:pink;
      }
    </style>
  </head>
  <body>
    <div class="main2">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
    </div>
  </body>
</html>

八、网格对齐方式

Grid子项在水平方向上与垂直方向上默认是stretch(拉伸)的,当不为grid子项指定宽高时将默认进行拉伸,填满单元格区域:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main{
        width:300px;
        height:300px;
        background:skyblue;
        display: grid;
        grid-template-columns: 100px 100px 100px;
        grid-template-rows: 100px 100px 100px;
      }
      .main div{
        background:pink;
      }

    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
      <div>7</div>
      <div>8</div>
      <div>9</div>
    </div>
  </body>
</html>

  • 由于指定grid容器为3行3列布局方式且单元格大小为100px * 100px所以默认情况下每个单元格在行与列之间进行拉伸,大小为100px * 100px

那么如果为Grid子项指定宽高且宽高小于每个单元格的大小呢?

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main{
        width:300px;
        height:300px;
        background:skyblue;
        display: grid;
        grid-template-columns: 100px 100px 100px;
        grid-template-rows: 100px 100px 100px;
      }
      .main div{
        width: 50px;
        height: 50px;
        background:pink;
      }

    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
      <div>7</div>
      <div>8</div>
      <div>9</div>
    </div>
  </body>
</html>

  • 可见此时Grid子项将位于单元格的左上角排列

8-1、水平方向上对齐方式

  • 通过justify-items改变Grid子项在“自己单元格”中水平方向上的对齐方式
  • 通过justify-content改变网格整体在grid容器中水平方向上的对齐方式

8-1-1、justify-items相关属性值

  • justify-items: end;
.main{
  width:300px;
  height:300px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  justify-items: end;
}

  • justify-items: center;
.main{
  width:300px;
  height:300px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  justify-items: center;
}

8-1-2、justify-content相关属性

  • justify-content: end;
.main{
  width:500px;
  height:500px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  justify-content: end;
}
.main div{
  background:pink;
}

  • justify-content: space-around;
.main{
  width:500px;
  height:500px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  justify-content: space-around;
}

  • justify-content: space-between;
.main{
  width:500px;
  height:500px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  justify-content: space-between;
}

  • justify-content: space-evenly;
.main{
  width:500px;
  height:500px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  justify-content: space-evenly;
}

8-2、垂直方向上对齐方式

  • 通过align-items改变Grid子项在“自己单元格”中垂直方向上的对齐方式
  • 通过align-content改变网格整体在grid容器中垂直方向上的对齐方式

8-2-1、align-items相关属性值

比如让grid子项位于自己的单元格的中部:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main{
        width:300px;
        height:300px;
        background:skyblue;
        display: grid;
        grid-template-columns: 100px 100px 100px;
        grid-template-rows: 100px 100px 100px;
        justify-items: center;
        align-items: center;
      }
      .main div{
        width: 50px;
        height: 50px;
        background:pink;
      }

    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
      <div>7</div>
      <div>8</div>
      <div>9</div>
    </div>
  </body>
</html>

8-2-2、align-content相关属性

示例:

.main{
  width:500px;
  height:500px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  justify-content: center;
  align-content: space-around;
}
.main div{
  background:pink;
}

8-3、对齐方式的复合写法

  • 可通过设置place-items来同时指定子项在“自己的单元格”中的水平方向上的对齐方式以及垂直方向上的对齐方式
    • place-items: [align-items] [justify-items]
.main{
  width:300px;
  height:300px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  /* justify-items: start;
  align-items: end; */
  place-items: end start;
}
  • 可通过place-content来同时指定网格整体在grid容器中水平方向的对齐方式以及垂直方向上的对齐方式
    • place-content: [align-content] [justify-content]
.main{
  width:500px;
  height:500px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  /* justify-content: center;
  align-content: space-around; */
  place-content: space-around center;
}

九、显式网格与隐式网格

  • 显式网格:即网格布局所需要的子项个数与真实存在的子项个数是一一对应的,比如网格是3行3列的,此时子项元素也是9个
  • 隐式网格:当网格布局所需要的子项个数要比真实存在的子项个数少时此时会产生隐式网格

9-1、隐式网格相关属性

比如,现在设置网格布局为1行3列,所需要的子项为3个,但此时有5个子项:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main{
        width:300px;
        height:300px;
        background:skyblue;
        display: grid;
        grid-template-columns: 100px 100px 100px;
        grid-template-rows: 100px;
      }
      .main div{
        background:pink;
        border:1px solid #ccc;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
    </div>
  </body>
</html>

  • 可见此时4、5占据的是隐式网格的位置,默认折行排列在了下方
  • 默认情况下,产生隐式网格,所以会自动折行,且高度默认是拉伸的
  • 可通过设置grid-auto-rows来指定隐式网格的高度:
.main{
  width:300px;
  height:300px;
  background:skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px;
  grid-auto-rows: 100px;
}

  • 可通过设置grid-auto-flow: column;来变为列产生隐式网格:

比如将grid容器设置为一列三行,但此时有5个grid子项,由于grid-auto-flow默认为按row(行产生隐式网格),所以如果不将grid-auto-flow设置为column的话,会展示成如下效果:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: 100px;
        grid-template-rows: 100px 100px 100px;
      }

      .main div {
        background: pink;
        border: 1px solid #ccc;
        box-sizing: border-box;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
    </div>
  </body>

</html>

此时就可以通过设置grid-auto-flow为column来使列产生隐式网格:

.main {
  width: 300px;
  height: 300px;
  background: skyblue;
  display: grid;
  grid-template-columns: 100px;
  grid-template-rows: 100px 100px 100px;
  /* column 就是列产生隐式网格 */
  grid-auto-flow: column;
}

可见,此时隐式网格列的宽度默认拉伸的,此时可以通过grid-auto-columns来调整隐式网格列的宽度:

.main {
  width: 300px;
  height: 300px;
  background: skyblue;
  display: grid;
  grid-template-columns: 100px;
  grid-template-rows: 100px 100px 100px;
  /* column 就是列产生隐式网格 */
  grid-auto-flow: column;
  /* 可以调节产生隐式网格的宽度 */
  grid-auto-columns: 100px;
}

9-2、隐式网格紧密排列

如果当子项不从第一个网格处排列时,如果不将隐式网格设置为紧密排列方式,前面会空出来位置,如:

<!DOCTYPE html>
<html lang="en">
  
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: 100px 100px 100px;
        grid-template-rows: 100px;
        grid-auto-rows: 100px;
      }
      
      .main div {
        background: pink;
        border: 1px solid #ccc;
        box-sizing: border-box;
      }
      
      .main div:nth-of-type(1) {
        grid-column-start: 2;
      }
    </style>
  </head>
  
  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
    </div>
  </body>
  
</html>

  • 此处通过grid-column-start设置第一个子项从第二列开始排列,这样的话后续的子项会从第一个子项后面开始排列

  • 如果想让后续的子项填上第一个空出来的位置,此时就要将隐式网格设置为“紧密的”排列方式

    • 设置方式为,grid-auto-flow: row dense; / grid-auto-flow: column dense;
.main {
  width: 300px;
  height: 300px;
  background: skyblue;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px;
  grid-auto-flow: row dense;
  /* dense 紧密的 */
  grid-auto-rows: 100px;
}

十、基于线的元素放置

10-1、基本使用方法

通过为grid子项设置grid-column-startgrid-column-endgrid-row-startgrid-row-end属性来表示grid子项所占据的区域的起始和终止位置,包括水平方向和垂直方向。

比如,在一个3行3列的九宫格中,Grid Line分为4条行分割线以及4条列分割线:

在控制台的Layout中勾选Grid overlays然后再Overlay display settings中选择“Show line numbers”即可看到行与列分割线的序号:

那么此时可通过改变改子项的grid-column-start、grid-column-end、grid-row-start、grid-row-end将其设置到九宫格的中心位置:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
      }

      .main div:nth-of-type(1) {
        background: pink;
        grid-column-start: 2;
        grid-column-end: 3;
        grid-row-start: 2;
        grid-row-end: 3;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
    </div>
  </body>

</html>

也可以方便得让子项跨行 / 跨列:

.main div:nth-of-type(1) {
  background: pink;
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 2;
  grid-row-end: 4;
}

10-2、注意事项

当存在另一个grid子项时,如果此时不为第一个子项设置grid-row-start与grid-row-end则此时第二个子项将会顺着第一个子项后面进行排列:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
      }

      .main div:nth-of-type(1) {
        background: pink;
        grid-column-start: 2;
        grid-column-end: 3;
      }

      .main div:nth-of-type(2) {
        background: slategray;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
    </div>
  </body>

</html>

如果为第一个子项设置grid-row-start与grid-row-end明确了其位置后,则第二个子项会填充空缺的位置:

.main div:nth-of-type(1) {
  background: pink;
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
}

10-3、通过设置span个数来指定所占行/列数

grid-column-start、grid-column-end、grid-row-start、grid-row-end除了后面跟数字来表示起始行/列与终止行/列的位置外,还可以跟 "span 数字" 来表示该子项所占行/列的个数:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
      }

      .main div:nth-of-type(1) {
        background: pink;
        grid-column-start: 2;
        grid-column-end: span 2;
        grid-row-start: span 3;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
    </div>
  </body>

</html>

表示该子项从第二个列线位置向后横跨两列,并横跨3行

10-4、为Grid Line命名

网格线默认是以数字的方式进行命名的,可以在为grid容器设置grid-template-columns与grid-template-rows属性时为网格线进行命名:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: [col1] 1fr [col2] 1fr [col3] 1fr [col4];
        grid-template-rows: [row1] 1fr [row2] 1fr [row3] 1fr [row4];
      }

      .main div:nth-of-type(1) {
        background: pink;
        grid-column-start: col2;
        grid-column-end: col4;
        grid-row-start: row2;
        grid-row-end: row3;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
    </div>
  </body>

</html>

10-5、属性简写方式

gird-row & grid-column

  • grid-row可对gird-row-start、grid-row-end进行简写
  • grid-column可对grid-column-start、grid-column-end进行简写

通过“/”作为分隔:

如grid-row: 2 / 3,第一个作为起始位置,第二个作为终止位置

grid-area

grid-area除了可以支持grid-temlate-areas设置的网格区域名称外,也可以作为grid-row-start、grid-row-end、grid-column-start、grid-column-end的属性的缩写

  • 也是通过“/”作为分隔符

    如grid-area: 2 / 2 / 4 / 3; 分别指的是grid-row-start: 2、grid-column-start: 2、grid-row-end: 4、grid-column-end: 3

.main div:nth-of-type(1) {
  background: pink;
  /* grid-column: 2 / 3;
  grid-row: 2 / 4; */
  /*等价于*/
  grid-area: 2 / 2 / 4 / 3;

}

十一、子项对齐方式

  • 通过justify-self可指定某一子项的水平对齐方式
  • 通过align-selft可指定某一子项的垂直对齐方式
  • place-self是align-self与justify-self两个属性的简写属性,可分别指定align-self与justify-self

justify-self使用方法与justify-items相同、align-selft使用方法与align-items相同,只不过justify-self、align-self是设置在grid子项上的;justify-items、align-items是设置在grid容器上的

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-rows: 1fr 1fr 1fr;
      }

      .main div:nth-of-type(1) {
        width: 50px;
        height: 50px;
        background: pink;
        grid-area: 2 / 2 / 3 / 3;
        /* justify-self: center;
        align-self: center; */
        place-self: center center;

      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
    </div>
  </body>

</html>

十二、repeat()与minmax()

12-1、repeat()

基本使用方法

用于指定可重复的数值

比如:将一个grid容器定义3列,每一列都是100px

.main {
  height: 400px;
  background: skyblue;
  display: grid;
  /* grid-template-columns: 100px 100px 100px; */
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: 100px;
}
  • 此时grid-template-columns: 100px 100px 100px就可以写成grid-template-columns: repeat(3, 100px):代表重复定义3列,每一列宽度为100px
  • 假如第一列150px,其余两列100px,也可以使用repeat语法进行简写:
.main {
  height: 400px;
  background: skyblue;
  display: grid;
  /* grid-template-columns: 150px 100px 100px; */
  grid-template-columns: 150px repeat(2, 100px);
  grid-template-rows: 100px;
}

自适应布局

使用repeat方法传入固定数值时,比如grid-template-columns: repeat(4, 100px)此时就固定为4列了,如果存在多余子项时,该子项将会被挤到下一行:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        height: 400px;
        background: skyblue;
        display: grid;
        grid-template-columns: repeat(3, 100px);
        grid-template-rows: 100px;
      }

      .main div {
        background: pink;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
    </div>
  </body>

</html>

此时我们可以将repeat方法的第一个值设置为auto-fill,这样该grid容器将会根据宽度自适应布局:

     .main {
        height: 400px;
        background: skyblue;
        display: grid;
        grid-template-columns: repeat(auto-fill, 100px);
        grid-template-rows: 100px;
      }

12-2、minmax()

用于设置最小和最大值的范围

基本使用方法

比如在1行3列布局的grid容器中,第一列与第三列固定为100px,第二列为自适应剩余空间:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        height: 400px;
        background: skyblue;
        display: grid;
        grid-template-columns: 100px 1fr 100px;
        grid-template-rows: 100px;
      }

      .main div {
        background: pink;
        border: 1px solid #ccc;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </div>
  </body>

</html>

但一旦将缩小窗口时,第二列也会变窄,直到缩小到第二列内容所需要的空间大小,如果想要让第二列缩小到指定大小后就不再缩小,此时就需要使用minmax方法:

.main {
  height: 400px;
  background: skyblue;
  display: grid;
  grid-template-columns: 100px minmax(100px, 1fr) 100px;
  grid-template-rows: 100px;
}

十三、网格布局案例

13-1、叠加布局

如上的布局方式,一般采用定位来实现,但是定位不太方便去设置元素的位置,使用网格布局可更加方便的将元素定位到想要的位置。

具体思路:

  • 在不给grid容器设置行与列时默认就是含有1个单元格的网格
  • 要实现叠加效果的话使多个元素占据同一个网格的区域即可
<!DOCTYPE html>
<html lang="en">
  
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 530px;
        height: 300px;
        background: skyblue;
        display: grid;
      }
    </style>
  </head>
  
  <body>
    <div class="main">
      <img src="./phone.png" alt="">
      <span>自制</span>
      <p>手机热卖中.....</p>
    </div>
  </body>
  
</html>

此时,img会占据网格区域,而span与p会各占一个隐式网格的区域

要实现叠加效果,就要让图片所占网格区域与文字所占网格区域为同一个区域:

.main {
  width: 530px;
  height: 300px;
  background: skyblue;
  display: grid;
}

.main img {
  grid-area: 1/1/1/1;
}

.main span {
  grid-area: 1/1/1/1;
  justify-self: end;
  align-self: end;
  margin: 5px;
  color: white;
}

.main p {
  grid-area: 1/1/1/1;
  align-self: center;
  margin: 0;
  padding: 0;
  background: rgba(0, 0, 0, 0.5);
  height: 30px;
  line-height: 30px;
  color: white;
}
  • 设置为同一个区域后可通过justify-selfalign-self去调整元素的位置

13-2、多种组合排列布局

利用网格布局中合并单元格的操作可以轻松实现以上布局。

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        width: 300px;
        height: 300px;
        background: skyblue;
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-template-rows: repeat(3, 1fr);
        gap: 5px;
      }

      .main div {
        background: pink;
      }

      .main div:nth-of-type(1) {
        grid-area: 1/1/span 2/span 2;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
    </div>
  </body>

</html>

  • 将网格布局为3行3列,然后将第一个子元素所占区域设置为从第一个网格线开始横跨2行2列即可实现此效果
  • 同时,也可以快捷调整第一个子元素的所占区域使得其在右下方
.main div:nth-of-type(1) {
  grid-area: 2/1/span 2/span 2;
}

其他子元素会填补空缺后依次排列开来

13-3、栅格布局

一般会将一行划分为12个栅格,每个容器通过分配不同数量的栅格数来占据不同的宽度。

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .row {
        background: skyblue;
        display: grid;
        grid-template-columns: repeat(12, 1fr);
        /*一行的高度设置为50px*/
        grid-template-rows: 50px;
        /*隐式网格行的高度也设置为50px*/
        grid-auto-rows: 50px;
      }

      .row div {
        background: pink;
        border: 1px solid rgb(96, 96, 96);
      }

      /*横跨1列*/
      .row .col-1 {
        grid-area: auto/auto/auto/span 1;
      }

      /*横跨2列*/
      .row .col-2 {
        grid-area: auto/auto/auto/span 2;
      }

      /*横跨3列*/
      .row .col-3 {
        grid-area: auto/auto/auto/span 3;
      }

      /*横跨4列*/
      .row .col-4 {
        grid-area: auto/auto/auto/span 4;
      }

      /*横跨5列*/
      .row .col-5 {
        grid-area: auto/auto/auto/span 5;
      }

      /*横跨6列*/
      .row .col-6 {
        grid-area: auto/auto/auto/span 6;
      }

      /*横跨7列*/
      .row .col-7 {
        grid-area: auto/auto/auto/span 7;
      }

      /*横跨8列*/
      .row .col-8 {
        grid-area: auto/auto/auto/span 8;
      }

      /*横跨9列*/
      .row .col-9 {
        grid-area: auto/auto/auto/span 9;
      }

      /*横跨10列*/
      .row .col-10 {
        grid-area: auto/auto/auto/span 10;
      }

      /*横跨11列*/
      .row .col-11 {
        grid-area: auto/auto/auto/span 11;
      }

      /*横跨12列*/
      .row .col-12 {
        grid-area: auto/auto/auto/span 12;
      }
    </style>
  </head>

  <body>
    <div class="row">
      <div class="col-6">1</div>
      <div class="col-3">2</div>
      <div class="col-4">3</div>
      <div class="col-12">4</div>
    </div>
  </body>

</html>

  • 注意这里将grid-row-start、grid-column-start、grid-row-end设置为auto的目的是让后续的子项跟在此子项的后面依次排列,所以不能写死

13-4、容器自适应行列布局

利用网格布局可轻松实现网格的行自适应布局与列自适应布局。

行自适应布局

实现思路:

  • 不为容器设置高度,让高度随着内容撑开
  • 为容器指定列数,不为容器指定行数
  • 由于默认情况下,隐式网格是按行产生的,所以为隐式网格指定行的高度即可
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .main {
            width: 300px;
            background: skyblue;
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            grid-auto-rows: 100px;
            gap: 5px;
        }

        .main div {
            background: pink;
        }

    </style>
</head>

<body>
    <div class="main">
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
        <div>5</div>
    </div>
</body>

</html>

此时,再追加5个子元素时:

列自适应布局

实现思路:

  • 不给容器设置具体的宽度,将容器变为inline-grid,使得容器可以随着内容自适应宽度
  • 为容器指定行数,不为容器指定列数
  • 将隐式网格产生方式设置为按列产生
  • 指定隐式网格列的宽度即可
<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
      .main {
        height: 300px;
        background: skyblue;
        display: inline-grid;
        grid-template-rows: repeat(3, 1fr);
        grid-auto-flow: column;
        grid-auto-columns: 100px;
        gap: 5px;
      }

      .main div {
        background: pink;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
      <div>6</div>
      <div>7</div>
      <div>8</div>
      <div>9</div>
      <div>10</div>
    </div>
  </body>

</html>