September 17, 2021

[CSS] Flex/Grid Layout Modules, part 12

[CSS] Flex/Grid Layout Modules, part 12
grip-template-areas 設定

今天繼續來講 Grid 單元,昨天提到了對齊基本用法,今天繼續來講對齊與留白。不過一開始,還是先解釋清楚關於格線與單元之間的事情。

總覺得 15 天就會結束了說(笑)。


單元與格線

Grid 容器提供了格線系統,然後每個格線將內容區塊化(blockification)後,產生了 Grid 單元。這是整個 Grid Layout 的運作方式。那麼,對於 Grid 單元來說,格線系統就類似一種邊界,可以指定 Grid 單元在哪些軌道上。

基本的樣式為,

樣式 可用值 預設值
grid-row-start, grid-row-end <軌道格線> auto
grid-column-start, grid-column-end <軌道格線> auto
grid-row <grid-row-start> / <grid-row-end>? auto
grid-column <grid-column-start> / <grid-column-end>? auto
grid-area 軌道區域名稱或 <grid-row> / <grid-column>? 集合,定義順序為 row-start column-start row-end column-end auto

指定軌道區域名稱

首先,軌道區域名稱比較容易理解,他是對應於 Grid 容器的 grid-template-areas 所指定的名稱,例如,

.grid-container {
    display: grid;
    
    grid-template-areas:
        "nav nav nav"
        "sidebar main main"
        "sidebar main main"
        "footer footer footer"
}

那麼當你想要把你的 Grid 單元放到指定區域名稱的時候,使用 grid-area 就會比較方便,

.grid-nav {
    grid-area: nav;
}

.grid-sidebar {
    grid-area: sidebar;
}

.grid-main {
    grid-area: main;
}

.grid-footer {
    grid-area: footer;
}
grip-template-areas 設定

不知道大家還記得在開始的時候提到的網格單元容器嗎?

不知道的自己去複習

當你使用 grid-template-areas 定義區塊,然後接著使用 grid-area 來指定自訂區域名稱的時候,基本上就等同於 指定一個軌道區域 給這個 Grid 單元使用,所以,基本上他可以被翻譯成網格軌道格線的定義。

我們拿剛剛的例子來看,

.grid-nav {
    grid-area: nav;
}

/* 等同於 */

.grid-nav {
    grid-area: 1 1 2 4;
}

/* 等同於 */

.grid-nav {
    grid-row: 1 / 2;
    grid-column: 1 / 4;
}

/* 等同於 */

.grid-nav {
    grid-row: nav-start / nav-end;
    grid-column: nav-start / nav-end;
}

/* 等同於 */

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

/* 等同於 */

.grid-nav {
    grid-row-start: nav-start;
    grid-row-end: nav-end;
    
    grid-column-start: nav-start;
    grid-column-end: nav-end;
}

所以說,這邊的定義就會是一個所謂的網格單元容器(Grid item container block),根據一開始提到的定位點問題,使用 grid-area 的時候,請留意你的 Grid 單元在使用 position: absolute 的情況。之前已經說過了,這邊就不再多做贅述。

我們回到 grid-area 這件事情上面。當我們使用了命名單元的時候,如同之前所提到的,會提供 4 條隱性格線。所以當你使用 nav-startnav-end 的時候也是會發生作用的。

忘記的人請回去複習謝謝

接著,這個網格單元容器跟軌道一樣,是一種邊界的概念,換句話說,他一樣沒有能力去侷限 Grid 單元本身的定義或內容是否不能超出邊界(軌道)。另外,當你的單元軌道使用的軌道名稱,不存在於 Grid 容器定義裡的話,會出現奇怪的問題。

那個奇怪的問題我上次也提過了,這邊就不贅述了。


指定 <軌道格線>

我們之前有聊到軌道跟格線,還有隱性格線的介紹,現在我們就把他用在 Grid 單元上面。軌道格線的定義方式有幾種,

可用值 說明
auto 不解釋。
<自訂軌道名稱> 請避開 -start, -end,其餘不解釋。
<數字> 將你所指定的 <數字> 的軌道,可以是負數。
<數字> <自訂軌道名稱> <自訂軌道名稱> 的軌道有複數數量時,該數字僅會計算相同名稱的軌道,如果數字是負數的話,計算方向就是反向,該數字不可為零 0
span [<數字>, <自訂軌道名稱>] 跨度(維度)的軌道,如果是 <數字> 則表示要 跨過多少軌道數量,如果是 <自訂軌道名稱> 則表示直接跨到該<自訂軌道名稱> 的軌道。該數字 不可為負數或 0

Grid 格線軌道這件事情之前已經有提過了,這邊就不再繼續解釋說過的東西。我們直接舉一些例子來看看使用方法,

.grid-container {
    display: grid;
    
    grid-template-columns: [foo] 1fr [boo] 1fr [qoo] 1fr [ooo];
    grid-template-rows: repeat(3, 1fr);
    
    grid-auto-rows: 100px;
}
基本的 Grid 容器與命名軌道

首先,基本的 Grid 單元軌道格線設定會是這樣,

.grid-item {
    grid-column-start: foo;
    grid-column-end: qoo;
    
    grid-row-start: 2;
    grid-row-end: 3;
}

/* 等同於 */

.grid-item {
    grid-column-start: foo;
    grid-column-end: qoo;
    
    grid-row-start: -3;
    grid-row-end: -2;
}
定義 Grid 單元空間

<數字> <自訂軌道名稱>

接著我們來聊 <數字> <自訂軌道名稱> 這個設定方式,他有一個先決條件,

當你的自訂軌道有複數相同的名稱時,此設定才會正常,不然一樣會觸發隱性軌道的設置。

我們舉幾個例子來看看,

.grid-container {
    display: grid;
    
    grid-template-columns: repeat(7, [foo] 1fr [qoo]);
    grid-template-rows: repeat(3, 1fr);
    
    grid-auto-rows: 100px;
}
複數軌道名稱

接著我們來看比較正常定義的狀態,

.grid-item-a {
    grid-column-start: foo;
    grid-column-end: 2 qoo;
    
    grid-row: auto;
}

好的,根據 <數字> <自訂軌道名稱> 的定義,我們的欄方向結束軌道是 第二個 qoo,所以你知道最後我們的網格單元會在那個位置上了嗎?

使用數字、軌道名稱來定義單元空間

如果算錯了怎麼辦?舉個例子來說,

.grid-item-b {
    grid-column-start: -3 foo;
    grid-column-end: -4 qoo;
    
    grid-row: auto;
}

阿我就怕被罵啊。

定義起始與結束同一個軌道時

如果起始與結束在同一個網格軌道上,網格單元會自動往 下一個軌道空間擺放

所以,剛剛寫錯的地方,他其實就是以下這樣的設定方式,

.grid-item-b {
    grid-column-start: -3 foo;
    grid-column-end: -3 qoo;
    
    grid-row: auto;
}

無論你的數字是正值還是負值,基本上遇到一樣的狀況時,網格系統就是會這樣去做處理。如果沒空間可以放的話,那麼就會出現隱性網格軌道,用來擺放應該放進去的位置。舉例來說,

/* 超出網格容器的軌道數量 */
.grid-item-b {
    grid-column-start: -9 foo;
    grid-column-end: 12 qoo;
    
    grid-row: auto;
}

圖片我就不放了,上面設定的結果就是你會獲得 12 條軌道。至於為什麼不要問我,稍微加點乘除一下就會知道了。


span [<數字>, <自訂軌道名稱>]

最後一種設定方式稱之為跨度(跨維度)的 Grid 單元設定。所謂的跨維度,意思就是你可以指定你要 跨過 多少個軌道,

  • span 3 表示跨過三個軌道
  • span foo 表示跨過命名軌道 foo

這個關鍵字 span 有兩種不同的呈現方式,你把他放在 -start-end 的兩種位置上時,他的操作方式會略有不同。我們先來看看使用 -end 的狀況,他比較容易理解,

.grid-item {
    grid-column-start: 1;
    grid-column-end: span 3;
    
    grid-row: auto;
}

我們在 grid-column-end 的設定是 span 3,他的意思就是,

grid-column-start 的設定開始,欄方向 往後 做跨度 3 個軌道的動作。如果是命名軌道,則是欄方向 往後 做 跨度直到 <命名軌道> 的動作。

軌道跨度設定

用數字的方式很容易理解,如果今天使用的是 <命名軌道> 呢?跟往常在使用命名軌道的邏輯是相同的,他只會計算 符合名稱的軌道,換句話說,如果他找不到你的軌道名稱,那麼就會觸發隱性軌道的事件發生。

我們先不談隱性軌道,單純以合法的方式來操作。在命名軌道的情況下,所謂的跨度的計算方式,在 -end 的設定方式下,他會往後找下一個符合命名軌道的軌道來做跨度的動作。所以,我們舉一個名稱比較多的軌道來當例子,會比較容易理解,

.grid-container {
    display: grid;
    
    grid-template-columns: [foo] 1fr [ooo] 1fr [ppp] 1fr [rrr] 1fr [boo] repeat(3, [foo] 1fr [qoo]);
    grid-template-rows: repeat(3, 1fr);
    
    grid-auto-rows: 100px;
}

.grid-item:nth-of-type(1) {
    grid-column-start: 1;
    grid-column-end: span foo;
    
    grid-row: auto;
}

.grid-item:nth-of-type(2) {
    grid-column-start: zoo;
    grid-column-end: span qoo;
    
    grid-row: auto;
}
命名格線跨度,使用在 -end 樣式

以上是使用在 -end 的情況,這個設定換成 grid-row-* 也是一樣的,你就把他想成換了一個方向就可以了。

接著來談談 -start 配上 span 這件事情,或許你會覺得困惑,所謂的跨度不就是 往後跨格線軌道 這樣嗎?理論上對,但這是在 -end 的情況下,如果使用在 -start 的話,就會變成 往前跨格線軌道 的操作方式,是的,方向跟 -end 相反。

-end 使用 span往後跨度
-start 使用 span往前跨度

如果可以理解的話,那麼以下兩種設定就只要瞭解 -end 的概念,然後把方向 反過來 就可以了,

  • grid-column-start: span 3grid-column-end 軌道 往前 跨度 3 個軌道。
  • grid-column-start: span boogrid-column-end 軌道 往前 跨度到 boo 軌道。

所以,如果這樣使用會是什麼呈現方式呢?我用剛剛的 grid-column-end 的例子,然後把他做成 grid-column-start 的寫法,然後 Grid 單元呈現會完全一樣。

命名格線跨度,使用在 -start 樣式

以上就是 span 關鍵字的相關用法。我這邊沒有提到異常的處理方式,之後有機會再拿回來講。畢竟,如果你只有 8 條格線軌道,你故意要跨 10 條軌道本來就會壞掉。所以這種情況我們暫時不在這裡提,隱性軌道的事情講起來太煩悶了。之後再來提會產生隱性軌道的事情吧。


關於 auto 與 Grid 單元軌道重疊

當你在設定一個比較複雜的格線系統時,可能有機會 算錯軌道 或是 打錯軌道名字 ,造成某些 Grid 單元在格線軌道設定的地方產生重疊。而這個重疊狀況,就會產生兩個單元互相覆蓋的情形。

.grid-container {
    display: grid;
    
    grid-template-columns: [foo] 1fr [ooo] 1fr [ppp] 1fr [rrr] 1fr [boo] repeat(3, [foo] 1fr [qoo]);
    grid-template-rows: repeat(3, 1fr);
    
    grid-auto-rows: 100px;
}

.grid-item:nth-of-type(1) {
    grid-column-start: 1;
    grid-column-end: 6;
    
    /* 指定在第一列 */
    grid-row: 1 / 2;
}

.grid-item:nth-of-type(2) {
    grid-column-start: foo;
    grid-column-end: span roo;
    
    /* 指定在第一列 */
    grid-row: 1 / 2;
}
指定在同一列,發生欄方向 Grid 單元覆蓋的情況

在這種情況下,如果使用 auto 的話,又會有不一樣的事情發生了,這些情況還需要看你是否有搭配 span 使用,組合起來會有各種不一樣的事情發生。

grid-column-start grid-column-end 結果
auto 3 定位在第 3 軌道,往前跨 1 個軌道,產生一個格線單元,並覆蓋相同位置的任何單元。
auto loo 定位在 loo 軌道上,往前跨 1 個軌道,產生一個格線單元,並覆蓋相同位置的任何單元。
auto span 3 從上一個相同位置軌道的 最後一個軌道,往後跨 3 個軌道,產生一個格線單元。
auto span qoo 此設置無效,僅會從上一個相同位置軌道的 最後一個軌道,往後跨 1 個軌道,產生一個格線單元。
1 auto 定位在第 1 軌道,往後跨 1 個軌道,產生一個格線單元,並覆蓋相同位置的任何單元。
loo auto 定位在 loo 軌道上,往後跨 1 個軌道,產生一個格線單元,並覆蓋相同位置的任何單元。
span 3 auto 從上一個相同位置軌道的 最後一個軌道,往後跨 3 個軌道,產生一個格線單元。
span qoo auto 此設置無效,僅會從上一個相同位置軌道的 最後一個軌道,往後跨 1 個軌道,產生一個格線單元。

以上的狀態換到 grid-row-* 也會是一樣的情況,僅方向不同而已。上述的情況我就不做圖片示意了,基本上稍微想像一下就好,我懶得作圖了(燦笑)。


官方沒有寫的例外

扣除 autospan 之外,還有一種設定是合法的,但是 w3c 官方在這邊並沒有列出來,根據文件的部分也就如同我上面描述的東西而已,這個寫法是,

<自訂軌道名稱> <數字>

這個寫法等同於 <數字> <自訂軌道名稱>,如果下次看到有人這樣寫不用太意外。算是冷知識說出來讓大家知道一下(笑)。


小記

這樣就結束了嗎?當然還有一點東西可以繼續嘴,對齊跟定位的問題我們明天會繼續講。


目錄與小節:
[CSS] Flex/Grid Layout Modules, part 0


鐵人賽同步放送:
https://ithelp.ithome.com.tw/articles/10264323