博客 / 詳情

返回

Grid佈局總結

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
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.