Grid布局总结

发布于:2023-03-18 ⋅ 阅读:(591) ⋅ 点赞:(0)

Grid简介

CSS Grid Layout(又叫Grid或者CSS Grid),它是一个二维网格的布局系统。在这之前经过了tables,float,positioninginline-block,但它们都相当于一个
hack,并且功能较少。Flex布局虽然是一个很棒的布局工具,但它是一维的,只能分开操作行和列。

Grid术语

Grid Container(容器)

当你对一个元素设置了display:grid后,它就是一个grid容器,如下:

<style>
  .container {
    display: grid
  }
</style>
<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容器后,该容器的所有直接子标签都是grid项目。这和flex布局是一样的

Grid Line(网格线)

它是构成grid布局的分界线。它们既可以是水平的(row grid lines)也可以是垂直的(column grid lines)

image.png

Grid Cell(网格单元)

由两条相邻的row grid lines(行)和两条相邻的column grid lines(列)组成的一个单元

image.png

Grid Track(网格轨道)

两条相邻网格线之间的空间。可以把它们看成网格的列或行。这里是第二行和第三行网格线之间的网格轨道

image.png

Grid Area(网格域)

由四条网格线组成的总空间,它可以由任意数量的grid cells组成

image.png

CSS Grid 容器中可用的属性

display

定义一个元素作为grid container并创建一个单列多行的grid formatting context(网格格式化上下文GFC), 行数由容器内的子元素(包括微元素和文本节点)决定

值:

  • grid - 生成一个块级grid
  • inline-grid - 生成一个内联grid

    display: grid | inline-grid

    grid-template-columns 、 grid-template-rows

    该属性定义的网格是一个显式网格, 使用grid-template-columnsgrid-template-rows属性定义网格的行和列(网格轨道), 都使用 空格分隔多个数值, 这些值代表网格轨道的大小,而且数值间的空格代表网格线

比如在容器上只显式设置grid-template-columns,那么grid-template-rows则默认为auto


  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .container {
      display: grid;
      grid-template-columns: 180px 20% auto 1fr 10vw;
    }
    .item {
      height: 100px;
    }
    .item1 {
      background: #e7c98c;
    }
    .item2 {
      background: #a21eee;
    }
    .item3 {
      background: #e690dd;
    }
    .item4 {
      background: #a7b7c7;
    }
    .item5 {
      background: #23cccc;
    }
    .item6 {
      background: #5fddc3;
    }
  </style>
  <div class="container">
    <div class="item item1">grid cell 1</div>
    <div class="item item2">grid cell 2</div>
    <div class="item item3">grid cell 3</div>
    <div class="item item4">grid cell 4</div>
    <div class="item item5">grid cell 5</div>
    <div class="item item6">grid cell 6</div>
  </div>

效果如图:
image.png
则表示定义了一个5列N行的网格,即将网格容器分为5列,每列宽度分别为180px,20%,auto,1fr,10vw等不同单位的值。

当多再添加一个网格项目时,则会创建5列2行的网格,如图:
image.png

然后在上面代码的基础上使用grid-template-rows显式指定网格轨道的尺寸,同时也会定义出轨道的数量(该属性的轨道指的就是)

    .container {
      display: grid;
      grid-template-columns: 180px 20% auto 1fr 10vw;
      grid-template-rows: 200px minmax(100px, auto) 20vh;
    }

这里就指定了一个5列3行的网格,即使是不满足有15个项目

image.png

同时,如果网格项目超过了你创建的网格单元数量,将会重新创建新的一行网格轨道,并以auto来计算网格轨道尺寸(又叫隐式网格)。

在使用grid-template-columnsgrid-template-rows时,默认会使用数字来指出网格线。按以上的代码为例,从左往右的column grid lines为1 ~ 6,从右往左为-1 ~ -6,从上往下的row grid lines为1~4, 从下往上为-1 ~ -4。

当然,也可以自己命名


    .container {
      display: grid;
      grid-template-columns:[line1] 180px [line2] 20% [line3] auto [line4] 1fr [line5] 10vw [line6];
      grid-template-rows: [row1] 200px [row2] minmax(100px, auto) [row3] 20vh [row4];
    }

同样,一条网格线也可以有多个名称


    .container {
      grid-template-rows: [row1-start] 200px [row1-end row2-start] minmax(100px, auto) [row2-end row3-start] 20vh [row3-end];
    }

为什么需要命名呢?因为想要创建一个符合需求的web布局,还需要网格项目属性grid-colunm,grid-row,grid-area指定内容所占网格域。这几个属性都是根据网格线的名称来指定网格域的所占空间,所以主要是为了可读性。比如定义一个如下的圣杯布局,如果用数字来确认内容的网格域,是不是很乱?


  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .container {
      display: grid;
      grid-template-columns:
        [header-col-start nav-col-start footer-col-start] 220px
        [nav-col-end main-col-start] 1fr
        [main-col-end aside-col-start] 200px
        [header-col-end aside-col-end footer-col-end];

      grid-template-rows:
        [header-row-start] 80px
        [header-row-end nav-row-start main-row-start aside-row-start] 400px
        [footer-row-start nav-row-end main-row-end aside-row-end] 80px
        [footer-row-end];
    }

    header {
      background: #e287ea;
      grid-column: header-col-start / header-col-end;
      grid-row: header-row-start/ header-row-end;
    }

    nav {
      background: #87eeee;
      grid-column: nav-col-start / nav-col-end;
      grid-row: nav-row-start/ nav-row-end;
    }
    main {
      background: #7633ae;
      grid-column: main-col-start / main-col-end;
      grid-row: main-row-start/ main-row-end;
    }
    aside {
      background: #ee323a;
      grid-column: aside-col-start / aside-col-end;
      grid-row: aside-row-start/ aside-row-end;
    }
    footer {
      background: #e67;
      grid-column: footer-col-start / footer-col-end;
      grid-row: footer-row-start/ footer-row-end;
    }
  </style>

  <div class="container">
    <header>header</header>
    <main>Main</main>
    <nav>Nav</nav>
    <aside>aside</aside>
    <footer>footer</footer>
  </div>

效果如下

image.png

grid-template-areas

不同于以上的grid-template-columnsgrid-template-rows,使用grid-template-areas同样也可以显式的创建一个网格布局,并且该语法使得网格结构更加的可视化,还不需要再命名网格线。我们还是以上面的圣杯布局为例,代码如下


  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .container {
      height: 100vh;
      display: grid;
      grid-template-columns: 220px 1fr 200px;
      grid-template-rows: 80px 1fr 80px;
      grid-template-areas:
        "header header header"
        "nav main aside"
        "footer footer footer";
    }

    header {
      grid-area: header;
      background: #e287ea;
    }

    nav {
      grid-area: nav;
      background: #87eeee;
    }
    main {
      grid-area: main;
      background: #7633ae;
    }
    aside {
      grid-area: aside;
      background: #ee323a;
    }
    footer {
      grid-area: footer;
      background: #e67;
    }
  </style>
  <div class="container">
    <header>header</header>
    <main>Main</main>
    <nav>Nav</nav>
    <aside>aside</aside>
    <footer>footer</footer>
  </div>

页面效果如下:

image.png

且使用这属性必须要遵循以下规则

  1. 描述完整的网格结构
  2. 使用.来标记一个空的grid cell
  3. 使用none表示没有定义grid areas

column-gap、grid-column-gap、row-gap、grid-row-gap

用于定义两个grid项目之间的间距,可以用任意css长度单位

    .container {
      /* standard */
      column-gap: 10px | 1rem | 1vw;
      row-gap: 10px | 1rem | 1vw;
      /* old */
      grid-column-gap: 10px | 1rem | 1vw;
      grid-row-gap: 10px | 1rem | 1vw;
    }

gap、grid-gap

是以上属性的简写,如果只定义了一个value,那么row-gapcolumn-gap都会采用该值

    .container {
      /* standard */
      gap: <row-gap> <column-gap>;

      /* old */
      grid-gap: <grid-row-gap> <grid-column-gap>;
    }

justify-items

沿着水平方向的轴线对齐网格项目,这个值适用于容器内的所有网格项目。

如果不设置该值,默认会拉伸所有的gird项目grid cell的大小

  1. 让项目在网格的起始位置对齐

    .container { justify-items: start; }

image.png

  1. 让项目在网格的结束位置对齐
.container { justify-items: end; }

image.png

  1. 让项目在网格的中间位置对齐
.container {
    justify-items: center;
}

image.png

  1. 拉伸项目至网格宽度

    .container { justify-items: stretch; }

image.png

align-items

该属性基本与justify-items相同,只不过对齐的方式相反,这个属性沿着竖直方向的轴线对齐网格项目。

  1. 沿竖直方向在网格(网格域)的开始位置对齐

    .container { align-items: start; }

    image.png

  2. 沿竖直方向在网格的结束位置对齐

    .container { align-items: end; }

image.png

  1. 沿竖直方向在网格的中间位置对齐
.container { align-items: center;}

image.png

  1. 沿竖直方向拉伸项目至网格的高度
.container { align-items: stretch;}

image.png

justify-content

和flex的一样,用于设置水平方向网格的对齐方式。即当网格总尺寸小于容器尺寸时使用

  1. 沿着容器的水平方向,对齐网格
.container { justify-content: start; }

image.png

2.沿容器的水平方向的结束位置,对齐网格

.container { justify-content: end; }

image.png

  1. 沿容器的水平方向的中间位置,对齐网格

    .container { justify-content: center; }

image.png

  1. 沿容器的水平方向拉伸网格

比如设置grid-template-columns: 100px auto 100px,第二列的网格没有设置一个固定尺寸,然后再设置以下的值(该值为默认值),则会拉伸。如果设置的是固定尺寸(px),则无法拉伸

.container { justify-content: stretch;}

image.png

  1. 沿容器的水平方向均匀分配剩余空间,项目与项目间的间隔距离比项目与容器边框的距离大1倍

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

image.png

  1. 沿容器水平方向两边排列项目
.container { justify-content: space-between; }

image.png

  1. 和space-around类似,不过该值无论是项目与项目间的间隔距离还是项目与容器边框的距离都会均匀分配

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

image.png

align-content

与justify-content相反,用于设置竖直方向grid cell的对齐方式。即当grid cell总尺寸小于grid container时使用

  1. 沿着容器的竖直方向,对齐网格
.container { align-content: start; }

image.png

2.沿容器的竖直方向的结束位置,对齐网格

.container { align-content: end; }

image.png

  1. 沿容器的竖直方向的中间位置,对齐网格

    .container { justify-content: center; }

image.png

  1. 沿容器的竖直方向拉伸网格

比如设置grid-template-rows: 100px auto 100px,第行列的网格没有设置一个固定尺寸,然后再设置以下的值(该值为默认值),则会拉伸。如果设置的是固定尺寸(px),则无法拉伸

.container { align-content: stretch;}

image.png

  1. 沿容器的竖直方向均匀分配剩余空间,项目与项目间的间隔距离比项目与容器边框的距离大1倍

    .container { align-content: space-around; }

image.png

  1. 沿容器竖直方向两边排列项目
.container { align-content: space-between; }

image.png

  1. 和space-around类似,不过该值无论是项目与项目间的间隔距离还是项目与容器边框的距离都会均匀分配

    .container { align-content: space-evenly; }

image.png

应用在grid项目上的属性

grid-column-start、grid-column-end、grid-row-start、grid-row-end

以上这几个属性用于控制项目的位置以及项目所占网格大小,还是用之前的圣杯布局做例子,
代码如下:


  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .container {
      display: grid;
      height: 100vh;
      grid-template-columns:
        [header-start nav-start footer-start] 220px
        [nav-end main-start ] 1fr
        [main-end aside-start] 220px
        [header-end aside-end footer-end];
      grid-template-rows:
        [header-start] 80px
        [header-end nav-start main-start aside-start] 1fr
        [nav-end main-end aside-end footer-start] 80px
        [footer-end];
    }


    header {
      grid-column-start: header-start;
      grid-column-end: header-end;
      grid-row-start: header-start;
      grid-row-end: header-end;
      background: #e287ea;
    }

    nav {
      grid-column-start: nav-start;
      grid-column-end: nav-end;
      grid-row-start: nav-start;
      grid-row-end: nav-end;
      background: #87eeee;
    }
    main {
      grid-column-start: main-start;
      grid-column-end: main-end;
      grid-row-start: main-start;
      grid-row-end: main-end;
      background: #7633ae;
    }
    aside {
      grid-column-start: aside-start;
      grid-column-end: aside-end;
      grid-row-start: aside-start;
      grid-row-end: aside-end;
      background: #ee323a;
    }
    footer {
      grid-column-start: footer-start;
      grid-column-end: footer-end;
      grid-row-start: footer-start;
      grid-row-end: footer-end;
      background: #e67;
    }
  </style>
  <div class="container">
    <header>header</header>
    <main>Main</main>
    <nav>Nav</nav>
    <aside>aside</aside>
    <footer>footer</footer>
  </div>

可以看到,代码量非常的大,所以不推荐使用,如果要使用这种方法,可以用下面的简写方式。

grid-column、grid-row

该属性是以上属性的简写方式,语法如下

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

值既可以使用默认的数值,也可以使用自定义的网格线名称,或者混用

具体代码示例可看之前的圣杯布局

grid-area(推荐写法)

它是以上属性的更加简写方式,需要配合grid-template-areas定义可视化的网格布局,然后来指定网格域。

具体示例也在之前的圣杯布局中有使用

justify-self

  1. 使网格项目按水平方向沿网格单元开始处排列
.item-a { justify-self: start; }

image.png

  1. 使网格项目按水平方向沿网格单元结束处排列

    .item-a { justify-self: end; }

image.png

  1. 使网格项目按水平方向沿网格单元中间处排列

    .item-a { justify-self: center; }

image.png

  1. 使网格项目拉伸至单元格水平方向的尺寸

    .item-a { justify-self: stretch; }

image.png

align-self

该属性和justify-self基本一致,只不过是竖直方向

place-self

该值为justify-selfalign-self的简写模式

.item-a {
  place-self: <align-self> / <justify-self>
}

fr单位

fr只能用于网格布局中,如grid-template-columns,grid-template-rows等属性上。

它的工作方式和flex-grow类似,根据网格容器中的可用空间比例来调整网格轨道大小。如下示例:

  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .container {
      display: grid;
      height: 100vh;
      grid-template-columns: 20fr 50fr 30fr;
      grid-template-rows: repeat(2, 50fr);
    }
    .item1 {
      background: #e7c98c;
    }
    .item2 {
      background: #a21eee;
    }
    .item3 {
      background: #e690dd;
    }
    .item4 {
      background: #a7b7c7;
    }
    .item5 {
      background: #23cccc;
    }
    .item6 {
      background: #5fddc3;
    }
  </style>
  <div class="container">
    <div class="item item1">grid cell 1</div>
    <div class="item item2">grid cell 2</div>
    <div class="item item3">grid cell 3</div>
    <div class="item item4">grid cell 4</div>
    <div class="item item5">grid cell 5</div>
    <div class="item item6">grid cell 6</div>
  </div>

image.png

由此可以得出:
网格宽度 = 网格轨道fr系数 * (剩余空间 / 总fr数量)

而且不同于设置百分比,使用fr再设置gap并不会溢出容器,全部使用百分比设置网格宽度容易导致溢出容器

grid布局中的函数

repeat()函数

接收两个参数:

  • 参数一:表重复次数,如grid-template-rows: repeat(3, 1fr)就等于grid-template-rows: 1fr 1fr 1fr,或者填写auto-fitauto-fill关键词
  • 参数二:为需要重复的值(可以为一个列表值或符合值),如grid-template-rows: repeat(3, 1fr 200px)就等于grid-template-rows: 1fr 200px 1fr 200px

当第一个参数使用关键词时,会更加多变。

auto-fill

在一行中尽可能的创建更多的列。只要能容纳新的列,就会自动创建隐式列,代码如下:


  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .container {
      display: grid;
      height: 100vh;
      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
      grid-template-rows: repeat(2, 50fr);
    }
    .item1 {
      background: #e7c98c;
    }
    .item2 {
      background: #a21eee;
    }
    .item3 {
      background: #e690dd;
    }
    .item4 {
      background: #a7b7c7;
    }
    .item5 {
      background: #23cccc;
    }
    .item6 {
      background: #5fddc3;
    }
  </style>

  <div class="container">
    <div class="item item1">grid cell 1</div>
    <div class="item item2">grid cell 2</div>
    <div class="item item3">grid cell 3</div>
    <div class="item item4">grid cell 4</div>
    <div class="item item5">grid cell 5</div>
    <div class="item item6">grid cell 6</div>
  </div>

从图中可以看出多创建了两个列(数量不是固定的)

image.png

auto-fit

根据当前已有的项目创建列,如果容器还有剩余空间,则将剩余空间均分给现有的列,自动变宽填满整个容器。当容器没有可用空间时另起一行,我们把上面的代码改一下

.container {
   grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

这时候,就不会创建更多的列,而是让每列平分剩余空间

image.png

minmax(MIN, MAX)

输出一个范围值,定义一个大于或等于MIN且小于或等于MAX的值的尺寸范围

参考资料

  1. https://css-tricks.com/snippets/css/complete-guide-grid/
  2. https://juejin.cn/book/7161370789680250917
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到