CSS-Grid 网格布局全攻略(从基础到进阶)

111 阅读6分钟

前言

如果说 Flex 布局是一维的“线性布局”,那么 Grid(网格布局) 就是真正意义上的“二维布局”。它能够同时处理行与列,让我们通过简单的代码就能实现极其复杂的页面结构。

一、 Grid 容器属性:定义你的网格空间

1. 开启网格布局

  • display: grid; :容器里面的元素为块级元素。
  • display: inline-grid; :容器里面的元素为行内元素。

2. 定义行与列 (grid-template-*)

通过 grid-template-columnsgrid-template-rows 划分网格。

  • 常用关键字:

    • repeat(count, value) :重复定义。例如 repeat(3, 1fr) 表示三列均分。
    • auto-fill:自动填充。让每一行/列尽可能容纳更多固定宽度的单元格。
    • fr (Fraction) :片段单位。表示网格剩余空间的比例关系。
    • minmax(min, max) :长度范围。例如 minmax(100px, 1fr)
    • auto:自适应,占满剩余宽度。

注意:不要单独使用grid-template-rows,单独使用grid布局可能会造成布局混乱,不可预测。

  • 使用实例:当网格单元格数量大于子元素数量时,多余单元格会保持空白,子元素不会因此被拉伸放大。 例如:定义一个 3列×4行 的网格,但只放入9个元素,剩余3个单元格会留空,而现有元素仍保持正常的网格比例尺寸
<!DOCTYPE html>
<html>
  <body>
    <div class="container">
      <div class="grid-container">
        <div class="div">1</div>
        <div class="div">2</div>
        <div class="div">3</div>
        <div class="div">4</div>
        <div class="div">5</div>
        <div class="div">6</div>
        <div class="div">7</div>
        <div class="div">8</div>
      </div>
    </div>

    <script></script>
  </body>

  <style>
    html,
    body {
      height: 100vh;
      margin: 0;
      padding: 0;
    }
    .container {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .grid-container {
      width: 500px;
      height: 800px;
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      grid-template-rows: repeat(4, 1fr);
    }
    .div {
      border: 1px solid salmon;
    }
  </style>
</html>

image.png image.png

3. 间距 (Gap)

注意:最新标准中已建议移除 grid- 前缀,直接使用 gap

  • row-gap:行间距。
  • column-gap:列间距。
  • gap:合写形式(<row-gap> <column-gap>)。
.grid-container {
  width: 500px;
  height: 800px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(4, 1fr);
  column-gap: 20px;
  row-gap: 20px;
}

image.png


二、 网格排列与对齐控制

1. 单元格内容对齐 (-items)

控制网格项在网格表内部的位置:

  • justify-items:网格中每行的水平对齐方式(start | end | center | stretch)。
  • align-items:格中每行的垂直对齐方式。
  • place-items:简写形式。

注意:当 Grid 子元素的宽高都超过了父容器时,justify-itemsalign-items可能会失效或不明显,所以尽量网格容器与子元素宽高可预知场景下使用。

实例:例如现在我给每个单元格都设置一个小于网格的宽高,这时就可直观看到它们的区别了 image.png image.png

<!DOCTYPE html>
<html>
  <body>
    <div class="container">
      <div class="grid-container">
        <div class="div">1</div>
        <div class="div">2</div>
        <div class="div">3</div>
        <div class="div">4</div>
        <div class="div">5</div>
        <div class="div">6</div>
        <div class="div">7</div>
        <div class="div">8</div>
      </div>
    </div>

    <script></script>
  </body>

  <style>
    html,
    body {
      height: 100vh;
      margin: 0;
      padding: 0;
    }
    .container {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .grid-container {
      width: 500px;
      height: 800px;
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      grid-template-rows: repeat(4, 1fr);
      column-gap: 20px;
      row-gap: 20px;

      align-items: center; /* 网格中每行的水平对齐方式 */
      justify-items: center;/* 网格中每行的垂直对齐方式 */
      border: 1px solid yellow;
    }
    .div:nth-child(2n) {
      width: 30px;
      height:30px;
      border: 1px solid salmon;
    }
    .div:nth-child(2n + 1) {
      width: 50px;
      height: 50px;
      border: 1px solid green;
    }
  </style>
</html>

2. 整个网格内容区域对齐 (-content)

在实际使用中,存在着网格内容区域大小和网格容器大小不一致的情况,而-content则是设置网格内容区域相对于容器的对齐方式。

  • justify-content:网格内容区域在水平位置相当于容器的对齐方式(space-between | space-around | space-evenly | strat | end | center |stretch(大小没有指定时,拉伸占据整个网格容器))。
  • align-content:网格内容区域在垂直方向相对于容器的对齐方式。
  • place-content:简写形式。

在上面的例子中,可以发现添加justify-content与align-content是无效的,因为网格内容区域总尺寸 = 容器尺寸,现在将网格中子项设置较大值与较小值,你就会发现区别:图左为网格内容区域总尺寸 > 容器尺寸,图右边为网格内容区域总尺寸 < 容器尺寸。

image.png image.png
 .container {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
  }
.grid-container {
  width: 500px;
  height: 800px;
  display: grid;
  grid-template-columns: repeat(3, 200px); /*  repeat(3, 100px) */
  grid-template-rows: repeat(4, 350px);   /*repeat(4, 150px); */
  column-gap: 20px;
  row-gap: 20px;

  align-items: center; /* 网格中每行的水平对齐方式 */
  justify-items: center;/* 网格中每行的垂直对齐方式 */


  justify-content: center; /*网格内容区域在水平位置相当于容器的对齐方式*/
  align-content: center;  /*网格内容区域在垂直方向相当于容器的对齐方式*/
  border: 1px solid yellow;
}

3. 排列顺序 (grid-auto-flow)

决定网格项如何自动填充到网格中。

  • row(默认):先行后列。
  • column:先列后行。


三、 项目属性:单个格子的自我修养

1. 基于网格线的定位

可以通过指定网格线来决定一个项目跨越多少行或列。

  • grid-column-start / end:元素左边框所在的垂直网格线/右边框所在的垂直网格线。
  • grid-row-start / end:元素上边框所在的水平网格线/下边框所在的水平网格线。
  • span 关键字:表示跨越的跨度。例如 grid-column: span 2;(跨越两列)。

image.png

<!DOCTYPE html>
<html>
  <body>
    <div class="container">
      <div class="grid-container">
        <div class="div">1</div>
        <div class="div">2</div>
        <div class="div">3</div>
        <div class="div">4</div>
        <div class="div">5</div>
        <div class="div">6</div>
        <div class="div">7</div>
        <div class="div">8</div>
      </div>
    </div>

    <script></script>
  </body>

  <style>
    html,
    body {
      height: 100vh;
      margin: 0;
      padding: 0;
    }
    .container {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .grid-container {
      width: 500px;
      height: 800px;
      display: grid;
      grid-template-columns: repeat(3, 1fr); /*  repeat(3, 100px) */
      grid-template-rows: repeat(4, 1fr); /*repeat(4, 150px); */
      column-gap: 20px;
      row-gap: 20px;
      /* grid-auto-flow: column; */
      align-items: center; /* 网格中每行的水平对齐方式 */
      justify-items: center; /* 网格中每行的垂直对齐方式 */

      justify-content: center; /*网格内容区域在水平位置相当于容器的对齐方式*/
      align-content: center; /*网格内容区域在垂直方向相当于容器的对齐方式*/
      border: 1px solid yellow;
    }
    .div:nth-child(2n) {
      width: 100%;
      height: 100%;
      border: 1px solid salmon;
    }
    .div:nth-child(2n + 1) {
      width: 100%;
      height: 100%;
      border: 1px solid green;
    }
    .div:last-child{
      background: red;
      grid-column-start:2;
      grid-column-end: 4;
      grid-row-start: 3;
      grid-row-end: 5;
    }
  </style>
</html>

2. 单个项目的对齐 (-self)

适用于网格内的的子元素,它会覆盖容器定义的 items 属性:

  • justify-self :置单元格内容的水平位置(左中右),跟justify-items属性的用法完全一致,但只作用于单个项目。取值:start | end | center | stretch(拉伸)
  • align-self:设置单元格内容的垂直位置(上中下)
  • place-self:是align-self属性和justify-self属性的合并简写形式
image.png image.png
<!DOCTYPE html>
<html>
  <body>
    <div class="container">
      <div class="grid-container">
        <div class="div">1</div>
        <div class="div">2</div>
        <div class="div">3</div>
        <div class="div">4</div>
        <div class="div">5</div>
        <div class="div">6</div>
        <div class="div">7</div>
        <div class="div">8</div>
      </div>
    </div>

    <script></script>
  </body>

  <style>
    html,
    body {
      height: 100vh;
      margin: 0;
      padding: 0;
    }
    .container {
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .grid-container {
      width: 500px;
      height: 800px;
      display: grid;
      grid-template-columns: repeat(3, 1fr); /*  repeat(3, 100px) */
      grid-template-rows: repeat(4, 1fr); /*repeat(4, 150px); */
      column-gap: 20px;
      row-gap: 20px;
      /* grid-auto-flow: column; */
      align-items: center; /* 网格中每行的水平对齐方式 */
      justify-items: center; /* 网格中每行的垂直对齐方式 */
      justify-self: start;
      justify-content: center; /*网格内容区域在水平位置相当于容器的对齐方式*/
      align-content: center; /*网格内容区域在垂直方向相当于容器的对齐方式*/
      border: 1px solid yellow;
    }
    .div{
      justify-self: end; 
      align-self: end;
    }
    .div:nth-child(2n) {
      width: 30px;
      height: 30px;
      border: 1px solid salmon;
    }
    .div:nth-child(2n + 1) {
      width: 50px;
      height: 50px;
      border: 1px solid green;
    }
    .div:last-child{
      width: 100%;
      height: 100%;
      background: red;
      grid-column-start:2;
      grid-column-end: 4;
      grid-row-start: 3;
      grid-row-end: 5;
    }
  </style>
</html>