[CSS] Flex/Grid Layout Modules, part 13

無設定單元的預設行為會填滿整個軌道

單元對齊跟留白的部分今天會繼續,定位的問題基本上不出亂子的話就如同昨天說明的。當然,如果再加上對齊跟留白,如果不小心也是會爆炸的。

對於留白問題,我一律設定為 0欸不是。


填滿(stretch)與留白(margin

我們現在已經會操作單元軌道來 框住 我們的 Grid 單元了,那麼,那些基本的單元對齊的部分應該使用上就不會有太大的問題。

如果忘記的請自行複習

但是呢,由於軌道邊界設定的關係,所以 Grid 容器指定的對齊、Grid 單元自行指定的對齊,跟 marginstretch 之間就會有不少互相影響的部分。之前有說過,當你使用 stretch 的時候,因為會預設 填滿 所以對齊這件事情基本上會覺得他 沒有任何效果

在完全沒有任何設定的 Grid 單元,他們所有的設定預設都會是 auto,也就是說,基本上所有的 Grid 單元會填滿每一個軌道空間,

.grid-container {
    display: grid;
    
    grid-template-columns: repeat(7, [foo] 1fr [qoo]);
    grid-template-rows: repeat(3, 1fr);
    
    grid-auto-rows: 100px;
}
<div class="grid-container">
    <div class="grid-item">1</div>
    <div class="grid-item">2</div>
    <div class="grid-item">3</div>
    <div class="grid-item">4</div>
    <div class="grid-item">5</div>
    <div class="grid-item">6</div>
    <div class="grid-item">7</div>    
</div>
無設定單元的預設行為會填滿整個軌道

所以在這種預設行為下,基本上你想要定義的對齊都 看不出什麼效果,換句話說,除非你明訂了 Grid 容器、Grid 單元所使用的軌道空間,與 Grid 單元本身的尺寸,你的對齊才會有效果。

所以,這種 stretch 的預設行為,在明確定義使用空間的情況下,會有什麼反應呢?

.grid-item:first-child {
    grid-column: 1 / 4;
    grid-row: 1 / 3;
    
    align-self: stretch;
    justify-self: stretch;
}

圖片我就不做了,上面就是把欄方向軸軌道 1 ~ 4,列方向軸軌道 1 ~ 3 這個區域填滿。

但是,

如果你使用了 margin 的話,他的填滿就會受到 margin 的影響,且,如同之前所說的,這個填滿設定一樣會受到 min-width, min-height, max-width, max-height 所影響。我們單純來看 margin 的例子,

.grid-item:first-child {
    grid-column: 1 / 4;
    grid-row: 1 / 3;
    
    align-self: stretch;
    justify-self: stretch;
    
    margin-left: 100px;
}
stretch 會受到 margin 的壓縮

你會看到這個 Grid 單元被壓縮了,我們之前有說過,在無指定尺寸的 Grid 單元,他所使用的尺寸演算方式會使用 fit-content 的計算方式來決定這個 Grid 單元的大小。所以,在一個合理的 margin 留白數值的設定下,Grid 單元的尺寸就會被壓縮,用以符合留白(margin)的設定。

如果在無指定尺寸下使用 auto 的關鍵字呢?這個時候就必須取決於 fit-content 所計算出來的結果,來決定這個 auto 的最終呈現結果。換句話說,會有以下兩種狀況,

  • fit-content 計算尺寸可填滿軌道,則 auto 數值為 0
  • fit-content 計算尺寸無法填滿軌道,則 auto 數值為 <軌道剩餘空間>
margin-left: auto 所呈現的方式

換句話說,margin 使用 auto 的效果就是將非指定尺寸的 Grid 單元做尺寸計算,而早先我們有提過,單元的非指定尺寸運算就是使用 fit-content,所以,在 auto 的情況下就會把整個 Grid 單元壓縮到 fit-content

所以,你會有一種錯覺,底下的設定為何沒對齊左邊?

.grid-item:first-child {
    grid-column: 1 / 4;
    grid-row: 1 / 3;
    
    align-self: stretch;
    justify-self: start;
    
    margin-left: auto;
}

不是你的錯覺
對於整個 Grid 軌道來說,他就是水平方向使用 start 對齊左邊,之所以內容被推到右邊,那是因為從 Grid 軌道的 start 開始,被放入了 margin-left: auto,而使無指定尺寸內容被壓縮到 fit-content 的關係。

我們如果跳離開 Grid 格線系統,單純的使用區塊元件來看,

單純 Box Module margin-left: 100px

這個狀況在一般的 Box Module 對齊就是這個方式(以一般 LTR 的文本狀況),所以,現在只是把這個 100px 換成 auto 而已,其實並沒有 對齊點不同 的情況。這也是一種很常見的 在邏輯與樣式設定上是有對齊的,但是在 視覺上 卻看起來沒有對齊 的情況。

舉例來說,

.grid-item:nth-of-type(1),
.grid-item:nth-of-type(2) {
    grid-column: 1 / 4;
    grid-row: auto;
    
    align-self: stretch;
    justify-self: start;
    
    margin-left: auto;
}
<div class="grid-container">
    <div class="grid-item">對齊點其實在左邊</div>
    <div class="grid-item">看起來卻向對齊了右邊</div>
</div>
其實對齊點設定是 start,但看起來像是 end

有鑑於絕大部分的人還是視覺動物,所以如果要精確對齊的話,基本上要太隨意使用 autostretch 這兩個設定,不然大多都是 你的對齊不是我的對齊 的這種鳥事。


列方向軌道定位問題

我們一直都在講欄方向的對齊、定位,雖然說絕大部分的情況,大多都可以轉個方向就能通用,但是,有些情況還是會讓你產生 為什麼會這樣? 的疑惑。

舉一個最常見的例子,

.grid-item:nth-of-type(1),
.grid-item:nth-of-type(2) {
    grid-column: 1 / 3;

    grid-row: auto;
}

我們把兩個單元定位在 欄方向的範圍,且大小完全相同 ,在這個情況下,你覺得他會發生覆蓋嗎?

不會!

我知道了,一定是我設定了 grid-row: auto 的關係!

不是!

那會發生什麼事情?

grid-column 重疊造成的 grid-row 排列

其實你把這個行為轉 90 度,把欄、列交換來看,你就知道為什麼了。由於我們太習慣了由左至右排列,而忽略了由上至下的這一層關係。所以會天真的以為,既然欄重疊了那就 往後放 就好啦?

不!
欄重疊了要往下放!
欄重疊了要往下放!
欄重疊了要往下放!

同樣的道理,

.grid-item:nth-of-type(1),
.grid-item:nth-of-type(2) {
    grid-row: 2 / 3;
}

我這次連 grid-column 都不設定了,請問會發生什麼事情呢?我已經指定了 重複的列 的軌道位置,那麼他會怎麼擺放這兩個 Grid 單元呢?

grid-row 重疊造成的 grid-column 排列

如果你有設定 grid-column 但使用的是 span 關鍵字,那麼也會造成雷同的效果。但是請不要同時指定開始與結束的位置,請使用 span <數字> 就好。請不要問我為什麼?

你同時指定開始、結束位置,就 等於完全重疊 了好嗎!

請不要這樣設定後還來問我為何沒有自動排!

我保證會敲死你!

.grid-item:nth-of-type(1),
.grid-item:nth-of-type(2) {
    grid-column: span 3;
    grid-row: 2 / 3;
}
使用 span 來造成跨度排列

span 這個關鍵字在一開始我們的 grid-column 重疊的例子上也是通用的,這邊我就不再附上圖片了。那麼,這樣會有什麼意外嗎?

有,而且不小心就會發生。

當你算錯軌道的時候,例如,我們的跨度寫成了 span 5

.grid-item:nth-of-type(1),
.grid-item:nth-of-type(2) {
    grid-column: span 5;
    grid-row: 2 / 3;
}

/* 或是 */

.grid-item:nth-of-type(1),
.grid-item:nth-of-type(2) {
    grid-column: 1 / 4;
    grid-row: span 5;
}

兩個方向如果跨度都超過 Grid 容器,隱性格線就會出現,此時,隱性軌道的寬度會依照你所設定的數值去走(grid-auto-columns, grid-auto-rows),如果沒有設定,那麼隱性軌道的寬度就會是 0。所以,當你不小心跨度跨過頭的時候,你就會瞬間多出好幾條網格格線出來。

這種時候,如果你有設定間隔(gap)的話,你就會發現在有限尺寸的方向,就是一般顯示裝置的寬度,最右邊多出了很多 gap 的寬度出來,我之前有提過了間隔尺寸會依照格線軌道而 永久存在不會被壓縮

row 方向就比較幸運一點,如果你的容器沒有指定列方向尺寸的話,基本上他就視為 無限長度 的方式將所需要的 Grid 軌道填滿正個容器。

但是,如果 row 方向有設定尺寸,也就是容器的高度(height)時,就沒那麼好運了。這種情況就很類似於把 row 方向轉去 column 一樣(把高度變成寬度)。

這種設定錯誤的情況會因為隱性軌道尺寸的設置而造成兩種不同的影響,

  • 不指定隱性軌道尺寸優先計算 span <數字> 的可用軌道,將整個軌道區域依照指定尺寸,或彈性係數 fr 依照 fit-content 來均分,並將不足的部分分配 0 的尺寸,絕大部分隱性軌道會分配到 0 尺寸。
  • 指定隱性軌道尺寸優先分配且保證 隱性軌道尺寸 的軌道空間,不足空間的部分會壓縮彈性係數 fr 的軌道空間,並使得符合 fit-content 尺寸,有部分軌道會分配到 0 的尺寸。

具體來說會如何呢?如果不設定隱性格線尺寸,那麼隱性格線就會被壓縮,

沒有指定隱性軌道尺寸的狀況

如果設定隱性格線尺寸,那麼隱性格線尺寸會優先佔用容器,

指定隱性軌道尺寸的狀況

如果是列方向的話,比較不會有奇怪的問題,但如果你限制了 Grid 容器的高度(height),那麼列方向如果在空間不足,出現隱性軌道的時候,就會有比較奇怪的狀況發生。

Grid 容器限制高度,在列方向產生隱性格線

由於間隔(gap)本身會佔據空間,所以在不設定隱性格線尺寸的情況下,會盡可能壓縮沒用到空間的列,但是,由於列方向的 fit-content 最小值是 0(除非你是直書模式),所以你從上圖會發現,我們原本的第二列內容,被壓縮到僅出現在間隔(gap)所佔據的空間內。

這就是所謂的 夾縫中求生存!

如果你有設定隱性格線尺寸,那麼狀況就剛好顛倒,如同欄方向(column)一樣,被壓縮的就會是原本設置彈性空間的部分,

限制容器尺寸,且指定隱性軌道尺寸的狀況

其實,如果你限制了容器的寬度(width),那麼一樣會發生類似的狀況。只是因為這邊的範例都以 width: 100% 為主,所以並沒有像是高度那麼明顯的情形發生。


小記

有沒有發現我壓根都沒講到對齊?因為那些關鍵字好像太容易,講起來頗無趣。我明天找個時間充版面貼一下好了,總得有個交代才行(笑)。


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


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

Hina Chen
偏執與強迫症的患者,算不上是無可救藥,只是我已經遇上我的良醫了。
Taipei