網格佈局的基本概念

CSS 網格佈局為 CSS 引入了一個二維網格系統。網格可以用來佈局主要的頁面區域或小的使用者介面元素。本指南介紹了 CSS 網格佈局以及 CSS 網格佈局規範中的術語。本概述中展示的功能將在本系列的其他指南中進行更詳細的解釋。

什麼是網格?

網格是一組定義行和列的相交的水平線和垂直線。元素可以被放置在這些行和列線組成的網格上。CSS 網格佈局具有以下特點:

固定和靈活的軌道尺寸

你可以建立具有固定軌道尺寸的網格——例如使用畫素。這將網格設定為指定的畫素,以適應你期望的佈局。你還可以使用百分比或為此目的設計的 fr 單位建立具有靈活尺寸的網格。

專案放置

你可以使用行號、名稱或透過指定網格的一個區域將專案放置在網格上的精確位置。網格還包含一種演算法,用於控制未在網格上明確指定位置的專案的放置。

建立額外的軌道以容納內容

你可以使用網格佈局定義一個顯式網格。網格佈局模組定義的功能提供了在需要時新增額外行和列的靈活性。其中包含了諸如“新增儘可能多的列以適應容器”等功能。

對齊控制

CSS 網格佈局和 CSS 盒模型對齊功能使我們能夠控制專案在放入網格區域後的對齊方式,以及整個網格的對齊方式。

控制重疊內容

可以將多個專案放置到一個網格單元格或區域中,並且它們可以部分重疊。然後可以使用 z-index 屬性控制這種分層。

網格是一種強大的佈局方法,當與 CSS 的其他部分(如 flexbox)結合使用時,可以幫助你建立響應式、靈活且易於訪問的佈局。這一切都始於在你的網格容器中建立一個網格。

網格容器

我們透過在一個元素上宣告 display: griddisplay: inline-grid 來建立一個網格容器。一旦我們這樣做了,該元素的所有直接子元素就變成了網格專案

在這個例子中,我們有一個類名為 wrapper 的容器 div。裡面嵌套了五個子元素。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>

我們使用 display: grid; 使 .wrapper 成為一個網格容器。

css
.wrapper {
  display: grid;
}

所有的直接子元素現在都是網格專案。在 Web 瀏覽器中,你不會看到這些專案在變成網格前後顯示上有任何差異,因為網格為這些專案建立了一個單列網格。如果你在瀏覽器的開發者工具中檢查網格,你可能會在 grid 值旁邊看到一個小圖示。點選它,在大多數瀏覽器中,該元素的網格將在瀏覽器視窗中疊加顯示。

Using the grid highlighter in Firefox DevTools to view a grid

在你學習和使用 CSS 網格佈局時,你的瀏覽器工具將讓你更直觀地瞭解網格的情況。

如果我們想讓它更像一個網格,我們需要新增列軌道。

網格軌道

我們使用 grid-template-rowsgrid-template-columns 屬性在網格上定義行和列。這些屬性定義了網格軌道網格軌道是網格上任意兩條相鄰線之間的空間。下圖顯示了一個高亮的軌道——這是我們網格的第一行軌道。

A box with 3 grid items. Above the three items is a solid light green area which is the track.

網格軌道在顯式網格中透過使用 grid-template-columnsgrid-template-rows 屬性或簡寫的 gridgrid-template 屬性來定義。當網格專案被放置在顯式網格建立的軌道之外時,軌道也會在隱式網格中被建立。

基本示例

我們可以透過新增 grid-template-columns 屬性,然後定義列軌道的大小,來為我們之前的例子新增列軌道。

我們現在建立了一個具有三個 200 畫素寬列軌道的網格。子專案將在這個網格上佈局,每個網格單元格中一個。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: 200px 200px 200px;
}

fr 單位

軌道可以使用任何長度單位來定義。網格還引入了一個額外的長度單位來幫助我們建立靈活的網格軌道。fr 單位表示網格容器中可用空間的一部分。下一個網格定義將建立三個等寬的軌道,它們會根據可用空間的大小而增長和縮小。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

不等大小

在這個例子中,我們建立了一個定義,其中包含一個 2fr 軌道和兩個 1fr 軌道。可用空間被分成四份。兩份給了第一個軌道,接下來的兩個軌道各一份。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
}

混合使用靈活尺寸和絕對尺寸

在最後一個例子中,我們混合使用了絕對尺寸的軌道和 fr 單位。第一個軌道是 500px,所以這個固定寬度會從可用空間中減去。剩餘的空間被分成三份,並按比例分配給兩個靈活軌道。

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: 500px 1fr 2fr;
}

使用 repeat() 表示法的軌道列表

具有許多軌道的大型網格可以使用 repeat() 表示法,來重複網格軌道列表的全部或一部分。例如,網格定義:

css
.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

也可以寫成:

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

Repeat 表示法可以用於軌道列表的一部分。在這個例子中,我們建立了一個 8 列網格;初始軌道是 20px,然後是一個重複 6 個 1fr 軌道的區域,最後是一個 20px 的軌道。

css
.wrapper {
  display: grid;
  grid-template-columns: 20px repeat(6, 1fr) 20px;
}

Repeat 表示法(repeat())使用軌道列表來建立重複的軌道模式。在這個例子中,網格將有 10 個軌道;一個 1fr 軌道後面跟著一個 2fr 軌道,這個模式重複五次。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(5, 1fr 2fr);
}

隱式網格和顯式網格

在建立我們的示例網格時,我們使用 grid-template-columns 屬性明確定義了我們的列軌道,網格會根據需要建立行來容納內容。列定義了顯式網格,而行是隱式網格的一部分。

顯式網格由使用 grid-template-columnsgrid-template-rows 定義的行和列組成。當內容被放置在顯式網格之外時(例如,透過繪製額外的網格線放入行中),隱式網格會擴充套件已定義的顯式網格。

如果你將某個專案放置在定義的網格之外,或者由於內容量需要更多的網格軌道,那麼網格會在隱式網格中建立行和列。這些隱式軌道預設是自動調整大小的,這意味著建立的行或列的大小受其內容和網格容器內可用自由空間的影響。auto 關鍵字允許生成的軌道適應內容,同時共享任何剩餘空間。

你也可以使用 grid-auto-rowsgrid-auto-columns 屬性為在隱式網格中建立的軌道定義一個固定大小。

在這個例子中,我們設定了 grid-auto-rows: 200px,確保在這個隱式網格中建立的軌道高度為 200px

html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px;
}

軌道大小調整和 minmax

在設定顯式網格或為自動建立的行或列定義大小時,我們可能希望給軌道一個最小尺寸,但同時確保它們能擴充套件以適應任何新增的內容。例如,我們可能希望我們的行永遠不會收縮到小於 100 畫素,但如果我們的內容高度拉伸到 300 畫素,我們希望行也拉伸到那個高度。這可以透過 minmax() 函式來解決。

在這個例子中,我們在 grid-auto-rows 屬性值中使用了 minmax()。透過設定 grid-auto-rows: minmax(100px, auto);,自動建立的行將至少有 100px 高,最大值為 auto。將 auto 設定為最大值允許軌道增長以適應其內容(直到其 max-content 大小),同時共享網格容器內的任何可用自由空間。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(100px, auto);
}

網格線

應該注意的是,當我們定義一個網格時,我們定義的是網格軌道,而不是網格線。然後,網格會給我們編號的線來用於定位專案。在我們的三列兩行的網格中,我們有四條列線。

Diagram showing numbered grid lines.

線的編號根據文件的書寫模式來確定。在從左到右的語言中,線 1 位於網格的左側。在從右到左的語言中,它位於網格的右側。線也可以被命名,這在使用命名網格線的網格佈局指南中討論。

根據線來定位專案

下面的例子演示了基本的基於線的放置;在放置專案時,我們的目標是線而不是軌道。我們將在使用基於線的放置的網格佈局指南中更詳細地探討這一點。

在這個例子中,我們的三列軌道網格上的前兩個專案是使用 grid-column-startgrid-column-endgrid-row-startgrid-row-end 屬性來放置的。從左到右,第一個專案從列線 1 開始,跨越到列線 4,在我們的例子中,這是網格最右邊的線。它從行線 1 開始,到行線 3 結束,因此跨越了兩個行軌道。

第二個專案從網格列線 1 開始,跨越一個軌道。這是預設行為,所以我們不需要指定結束線。它也從行線 3 到行線 5 跨越了兩個行軌道。其他專案將把自己放置在網格的空閒空間中。

html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
  <div class="box5">Five</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}

.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
}

.box2 {
  grid-column-start: 1;
  grid-row-start: 3;
  grid-row-end: 5;
}

使用你的開發者工具中的網格檢查器,看看專案是如何根據網格線定位的。

線定位的簡寫

上面使用的長手寫值可以用 grid-column 簡寫來壓縮列的設定,用 grid-row 簡寫來壓縮行的設定。下面的例子會產生與前面程式碼相同的定位,但 CSS 少得多。斜槓(/)前面的值是開始線,後面的值是結束線。

如果區域只跨越一個軌道,你可以省略結束值。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}

.box1 {
  grid-column: 1 / 4;
  grid-row: 1 / 3;
}

.box2 {
  grid-column: 1;
  grid-row: 3 / 5;
}

網格單元格

網格單元格是網格上的最小單位。從概念上講,它就像一個表格單元格。正如我們在之前的例子中看到的,一旦一個父元素被定義為網格,其子專案將自動在定義的網格中各自佔據一個單元格。在下圖中,網格的第一個單元格被高亮顯示。

The first cell of the grid highlighted

網格區域

專案可以跨越一個或多個單元格,無論是按行還是按列,這就建立了一個網格區域。網格區域必須是矩形的——例如,不可能建立一個 L 形的區域。高亮的網格區域跨越了兩個行軌道和兩個列軌道。

A grid area

間距

可以使用 column-gaprow-gap 屬性,或者簡寫的 gap 屬性,在網格單元格之間建立間距通道。在下面的例子中,我們在列之間添加了 10 畫素的間距,在行之間添加了 1em 的間距。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: 10px;
  row-gap: 1em;
}
html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>

任何由間距使用的空間將在空間分配給靈活長度的 fr 軌道之前被計算,並且在尺寸調整方面,間距的作用就像一個常規的網格軌道,但是你不能在間距中放置任何東西。在基於線的定位方面,間距就像一條粗的、透明的線。

巢狀網格

一個網格專案可以成為一個網格容器。在下面的例子中,我們擴充套件了之前看到的帶有兩個定位項的三列網格,為第一個網格專案添加了子專案。由於這些巢狀的專案不是網格的直接子元素,它們不參與網格佈局,因此以正常的文件流顯示。

Nested grid in flow

不使用 subgrid 的巢狀

如果我們將 box1 設定為 display: grid,我們可以給它一個軌道定義,它也會成為一個網格。然後專案會佈局在這個新的網格上。

css
.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
html
<div class="wrapper">
  <div class="box box1">
    <div class="nested">a</div>
    <div class="nested">b</div>
    <div class="nested">c</div>
  </div>
  <div class="box box2">Two</div>
  <div class="box box3">Three</div>
  <div class="box box4">Four</div>
  <div class="box box5">Five</div>
</div>
css
* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  gap: 3px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.box {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}

.box1 {
  grid-column: 1 / 4;
}

.nested {
  border: 2px solid #ffec99;
  border-radius: 5px;
  background-color: #fff9db;
  padding: 1em;
}

在這種情況下,巢狀的網格與父網格沒有關係。正如你在例子中看到的,它沒有繼承父網格的 gap,並且巢狀網格中的線與父網格中的線不對齊。

子網格

除了常規網格,我們還可以建立子網格subgrid 值讓我們能夠建立使用父網格軌道定義的巢狀網格。

要使用它們,我們編輯上面的巢狀網格例子,將 grid-template-columns: repeat(3, 1fr) 的軌道定義更改為 grid-template-columns: subgrid。然後,巢狀的網格使用父網格的軌道來佈局專案。

css
.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
  display: grid;
  grid-template-columns: subgrid;
}

使用 z-index 分層專案

網格專案可以佔據同一個單元格,在這種情況下,我們可以使用 z-index 屬性來控制重疊專案堆疊的順序。

不使用 z-index 的重疊

如果我們回到那個透過行號定位專案的例子,我們可以修改它,使兩個專案重疊。

html
<div class="wrapper">
  <div class="box box1">One</div>
  <div class="box box2">Two</div>
  <div class="box box3">Three</div>
  <div class="box box4">Four</div>
  <div class="box box5">Five</div>
</div>
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}

.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
}

.box2 {
  grid-column-start: 1;
  grid-row-start: 2;
  grid-row-end: 4;
}

專案 box2 現在與 box1 重疊,它顯示在上面,因為它在原始碼順序中靠後。

控制順序

我們可以透過使用 z-index 屬性來控制專案堆疊的順序——就像定位專案一樣。如果我們給 box2 一個比 box1 更低的 z-index,它將在堆疊中顯示在 box1 下方。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}

.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
  z-index: 2;
}

.box2 {
  grid-column-start: 1;
  grid-row-start: 2;
  grid-row-end: 4;
  z-index: 1;
}

後續步驟

在本概述中,我們非常快速地看了一下網格佈局的可能性。探索並嘗試這些程式碼示例,然後繼續閱讀指南網格佈局與其他佈局方法的關係,在那裡我們將真正開始深入研究 CSS 網格佈局的細節。