網格模板區域

基於線的網格佈局指南中,我們瞭解了網格線以及如何根據這些線來定位專案。當你使用 CSS 網格佈局時,你總會用到線,這是一種在網格上放置專案的直接方法。然而,還有另一種方法可用於在網格上定位專案,你可以單獨使用它,也可以與基於線的定位結合使用。這種方法是使用命名的模板區域來放置專案。你很快就會明白為什麼我們有時稱之為網格佈局的“ASCII 藝術”方法!

命名網格區域

你已經遇到過 grid-area 屬性了。這個屬性的值可以包含用於定位一個網格區域的所有四條線。

css
.box1 {
  grid-area: 1 / 1 / 4 / 2;
}

當我們定義所有四條線時,我們實際上是透過指定包圍該區域的線來定義這個區域。

The grid area defined by lines

我們也可以透過給一個區域命名,然後在 grid-template-areas 屬性的值中指定該區域的位置來定義一個區域。你可以隨意選擇你想要的區域名稱。例如,如果我們希望建立下面所示的佈局,我們可以確定四個主要區域。

  • 頁首(header)
  • 頁尾(footer)
  • 側邊欄(sidebar)
  • 主內容區(main content)

An image showing a two column layout with header and footer

透過 grid-area 屬性,我們可以給這些區域分別命名。這本身並不會建立任何佈局。相反,它只是提供了可在佈局中使用的命名區域。

css
.header {
  grid-area: hd;
}
.footer {
  grid-area: ft;
}
.content {
  grid-area: main;
}
.sidebar {
  grid-area: sd;
}

定義了這些名稱後,我們就可以建立佈局了。這次,我們不是在專案本身上使用行號來放置專案,而是在網格容器上建立整個佈局。這裡我們建立了一個 9 列的網格,並指定 hdft 區域跨越所有 9 列,而 sd 跨越三列,main 跨越六列。每個區域只跨越一行。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-auto-rows: minmax(100px, auto);
  grid-template-areas:
    "hd hd hd hd   hd   hd   hd   hd   hd"
    "sd sd sd main main main main main main"
    "ft ft ft ft   ft   ft   ft   ft   ft";
}
html
<div class="wrapper">
  <div class="header">Header</div>
  <div class="sidebar">Sidebar</div>
  <div class="content">Content</div>
  <div class="footer">Footer</div>
</div>

使用這種方法,我們完全不需要在單個網格項上指定任何東西,一切都在我們的網格容器上完成。我們可以看到佈局被描述為 grid-template-areas 屬性的值。

留空網格單元格

在這個例子中,我們用區域完全填滿了網格,沒有留下任何空白。但是,你也可以用這種佈局方法將網格單元格留空。要留空一個單元格,請使用句點字元 .。如果我們只想讓頁尾直接顯示在主內容下方,我們就需要將側邊欄下方的三個單元格留空。

css
.header {
  grid-area: hd;
}
.footer {
  grid-area: ft;
}
.content {
  grid-area: main;
}
.sidebar {
  grid-area: sd;
}
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-auto-rows: minmax(100px, auto);
  grid-template-areas:
    "hd hd hd hd   hd   hd   hd   hd   hd"
    "sd sd sd main main main main main main"
    ".  .  .  ft   ft   ft   ft   ft   ft";
}
html
<div class="wrapper">
  <div class="header">Header</div>
  <div class="sidebar">Sidebar</div>
  <div class="content">Content</div>
  <div class="footer">Footer</div>
</div>

為了使佈局更整潔,我們可以使用多個 . 字元。只要句點之間至少有一個空格,它就會被算作一個單元格。對於複雜的佈局,讓行和列整齊對齊是有好處的。這意味著你可以直接在 CSS 中看到這個佈局的樣子。

跨越多個單元格

在我們的例子中,每個區域都跨越了多個網格單元格,我們透過用空格分隔並多次重複該網格區域的名稱來實現這一點。你可以在 grid-template-areas 的值中新增額外的空格來保持列的整齊對齊。你可以看到我們已經這樣做了,使得 hdft 區域與 main 對齊。

透過連結區域名稱建立的區域必須是矩形的,目前還沒有辦法建立一個 L 形的區域。規範確實提到未來的版本可能會提供這個功能。然而,你可以像跨越列一樣輕鬆地跨越行。例如,我們可以透過將 . 替換為 sd,使我們的側邊欄向下延伸到頁尾的末尾。

css
.header {
  grid-area: hd;
}
.footer {
  grid-area: ft;
}
.content {
  grid-area: main;
}
.sidebar {
  grid-area: sd;
}
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-auto-rows: minmax(100px, auto);
  grid-template-areas:
    "hd hd hd hd   hd   hd   hd   hd   hd"
    "sd sd sd main main main main main main"
    "sd sd sd  ft  ft   ft   ft   ft   ft";
}

grid-template-areas 的值必須顯示一個完整的網格,否則它是無效的(並且該屬性會被忽略)。這意味著你每一行必須有相同數量的單元格,如果是空的,則用一個句點字元來表示該單元格將被留空。如果你的區域不是矩形的,你也會建立一個無效的網格。

使用媒體查詢重新定義網格

由於我們的佈局現在包含在 CSS 的一個部分中,這使得在不同的斷點處進行更改變得非常容易。你可以透過重新定義網格、網格上專案的位置,或者兩者同時進行來實現這一點。

在這樣做時,請在任何媒體查詢之外定義你的區域名稱。這樣,無論內容區域被放置在網格的哪個位置,它都將始終被稱為 main

對於我們上面的佈局,我們可能希望在窄寬度下有一個非常基本的佈局,定義一個單列網格,並將我們的四個專案堆疊成四行。

css
.header {
  grid-area: hd;
}
.footer {
  grid-area: ft;
}
.content {
  grid-area: main;
}
.sidebar {
  grid-area: sd;
}

.wrapper {
  display: grid;
  grid-auto-rows: minmax(100px, auto);
  grid-template-columns: 1fr;
  grid-template-areas:
    "hd"
    "main"
    "sd"
    "ft";
}

然後我們可以在 媒體查詢 中重新定義該佈局,以變為我們的兩列布局,如果可用空間更寬,甚至可以將其變為三列布局。請注意,對於寬佈局,我們保留了九列的軌道網格,僅使用 grid-template-areas 重新定義了專案的位置。

css
@media (width >= 30em) {
  .wrapper {
    grid-template-columns: repeat(9, 1fr);
    grid-template-areas:
      "hd hd hd hd   hd   hd   hd   hd   hd"
      "sd sd sd main main main main main main"
      "sd sd sd  ft  ft   ft   ft   ft   ft";
  }
}
@media (width >= 60em) {
  .wrapper {
    grid-template-areas:
      "hd hd hd   hd   hd   hd   hd   hd hd"
      "sd sd main main main main main ft ft";
  }
}

為 UI 元素使用 grid-template-areas

你會在網上找到的許多網格示例都假定你會將網格用於主頁面佈局,然而,網格對於小元素和大元素同樣有用。使用 grid-template-areas 可能特別好,因為在程式碼中很容易看到你的元素長什麼樣。

媒體物件示例

舉個例子,我們可以建立一個“媒體物件”。這是一個元件,一側有空間放置影像或其他媒體,另一側是內容。影像可以顯示在盒子的右側或左側。

Images showing an example media object design

我們的網格是一個兩列軌道網格,影像的列大小為 1fr,文字為 3fr。如果你想要一個固定寬度的影像區域,那麼你可以將影像列設定為畫素寬度,併為文字區域分配 1fr1fr 的單個列軌道將佔據剩餘的空間。

我們給影像區域一個名為 img 的網格區域名稱,給文字區域一個名為 content 的名稱,然後我們可以使用 grid-template-areas 屬性來佈局它們。

css
* {
  box-sizing: border-box;
}

.media {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  max-width: 400px;
  display: grid;
  grid-template-columns: 1fr 3fr;
  grid-template-areas: "img content";
  margin-bottom: 1em;
}

.media .image {
  grid-area: img;
  background-color: #ffd8a8;
}

.media .text {
  grid-area: content;
  padding: 10px;
}
html
<div class="media">
  <div class="image"></div>
  <div class="text">
    This is a media object example. We can use grid-template-areas to switch
    around the image and text part of the media object.
  </div>
</div>

將影像顯示在盒子的另一側

我們可能希望能夠將我們的盒子以相反的方式顯示影像。為此,我們重新定義網格,將 1fr 軌道放在最後,並翻轉 grid-template-areas 中的值。

css
* {
  box-sizing: border-box;
}

.media {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  max-width: 400px;
  display: grid;
  grid-template-columns: 1fr 3fr;
  grid-template-areas: "img content";
  margin-bottom: 1em;
}

.media.flipped {
  grid-template-columns: 3fr 1fr;
  grid-template-areas: "content img";
}

.media .image {
  grid-area: img;
  background-color: #ffd8a8;
}

.media .text {
  grid-area: content;
  padding: 10px;
}
html
<div class="media flipped">
  <div class="image"></div>
  <div class="text">
    This is a media object example. We can use grid-template-areas to switch
    around the image and text part of the media object.
  </div>
</div>

網格定義簡寫

在看過了在網格上放置專案的各種方法以及許多用於定義網格的屬性之後,現在是時候看一看幾個可用於在一行 CSS 中定義網格及其許多相關內容的簡寫屬性了。

這些簡寫屬性可能很快就會變得讓其他開發者,甚至未來的你難以閱讀。然而,它們是規範的一部分,你很可能會在示例中或在其他開發者的使用中遇到它們,即使你選擇不使用它們。

在使用任何簡寫屬性之前,值得記住的是,簡寫不僅能讓你一次性設定多個屬性,它們還會將你沒有(或不能)在簡寫中設定的所有內容**重置**為其初始值。因此,如果你使用簡寫,請注意它可能會重置你在別處應用的設定。

網格容器的兩個簡寫屬性是顯式網格簡寫 grid-template 和網格定義簡寫 grid

grid-template

grid-template 簡寫屬性設定了以下完整屬性:

該屬性被稱為*顯式網格簡寫*,因為它設定的是你在定義顯式網格時控制的值,而不是那些影響任何可能建立的隱式行或列軌道的值。

以下程式碼使用 grid-template 建立了一個佈局,該佈局與本指南前面建立的佈局相同。

css
.wrapper {
  display: grid;
  grid-template:
    "hd hd hd hd   hd   hd   hd   hd   hd" minmax(100px, auto)
    "sd sd sd main main main main main main" minmax(100px, auto)
    "ft ft ft ft   ft   ft   ft   ft   ft" minmax(100px, auto)
    / 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}

第一個值是我們的 grid-template-areas 值,但我們還在每行的末尾聲明瞭行的大小。這就是 minmax(100px, auto) 的作用。

然後在 grid-template-areas 之後有一個正斜槓,之後是列軌道的顯式軌道列表。

grid

grid 簡寫更進一步,還設定了隱式網格使用的屬性。所以你將設定:

你可以以與 grid-template 簡寫完全相同的方式使用此語法。只需注意,這樣做會重置該屬性設定的其他值。

css
.wrapper {
  display: grid;
  grid:
    "hd hd hd hd   hd   hd   hd   hd   hd" minmax(100px, auto)
    "sd sd sd main main main main main main" minmax(100px, auto)
    "ft ft ft ft   ft   ft   ft   ft   ft" minmax(100px, auto)
    / 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}

當我們學習網格佈局中的自動放置grid-auto-flow 屬性時,我們將重新審視此簡寫提供的其他功能。

後續步驟

如果你一直在學習網格指南,你應該能夠使用基於線的放置命名區域來建立網格佈局。現在讓我們來看看如何使用命名網格線建立網格佈局