September 15, 2021

[CSS] Flex/Grid Layout Modules, part 10

[CSS] Flex/Grid Layout Modules, part 10
使用 gap 的容器

來到了 30 天的三分之一,然後我才剛講完網格容器而已,但是,剩下的東西也不多了,好像要寫滿 30 篇難度有點高。

只好多寫一點廢話了。


間隔、間隔、間隔

當兵有呼過拐拐的應該知道我在講什麼。

這邊的 gap 其實跟 Flexbox 其實是同一套,而且特性也一樣。

Gaps Between Boxes
CSS Box Alignment Module Level 3

不要問我為什麼大家都跟 Box Alignment Module 有關。如果大家有耐心去看官方文件的話,會發現 Box Alignment Module 超級無敵霹靂長,幾乎是囊括了所有跟對齊有關,跟對齊沒有那麼相關,跟對齊幾乎無關的東西(疑)。

例如 gap 我就不懂跟對齊有什麼關係?

基本上在 Grid 容器裡面,間隔的寫法跟 Flexbox 如出一轍,

.grid-container {
    display: grid;
    
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(3, 1fr);
    
    column-gap: 10px;
    row-gap: 10px;
}
使用 gap 的容器

與 Flexbox 相同的地方是,間隔的尺寸並不會被壓縮,且也是算在整個容器尺寸裡面。所以,當你設定了容器尺寸的時候,請留意 gap 的尺寸是否會壓縮到你的 Grid 單元,爾或是,你的 Grid 單元與 gap 的尺寸總和,是否能容納在 Grid 容器內。

同樣的狀況,當你使用 repeat()auto-fillauto-fit 的時候,也會因為 gap 的尺寸設定,而導致你的每個欄或列能放入的數量不同。

我們快速的舉幾個例子給大家看看,

.grid-container {
    display: grid;
    
    grid-template-columns: repeat(3, 200px);
    grid-template-rows: repeat(3, 200px);
    
    column-gap: 10px;
    row-gap: 10px;
    
    width: 600px;
    height: 600px;
}

在這種時候,其實你的 Grid 容器真實尺寸是,

200px x 3 + 10px x 2 = 620px

而你將容器設定為 600px 時,基本上他還是會依照 Grid 的規範畫出容器,但是容器本身會限制在 600px 的尺寸內,

固定容器尺寸時,間隔可能會造成單元超出容器尺寸

當然,你也可以使用彈性尺寸設計來避開這件事情,但是,由於 gap 的絕對優勢,所以你的 Grid 單元會被 壓縮。壓縮的方式跟分配 fr 的方式是雷同的,但這裡的彈性尺寸總和需要扣除固定尺寸的限制,

Grid 單元尺寸 = <剩餘空間> * <彈性尺寸> / <彈性尺寸總和(扣除固定尺寸的情況)>

剩餘空間 = 容器總空間 - (若存在則扣除固定尺寸單元) - gap 尺寸

舉例來說,

.grid-container {
    display: grid;
    
    grid-template-columns: minmax(200px, 1fr) 2fr 1fr;
    
    column-gap: 10px;
    
    width: 600px;
}

最終我們得到的後面兩個尺寸就分別是,

  • 2fr 最終尺寸 (600 - 20) * 2 / 3 = 253.33px
  • 1fr 最終尺寸 (600 - 20) * 1 / 3 = 126.66px

為什麼?

因為上述的設定一定會觸發 minmax() 並且將最小值鎖定在 200px

另外針對 auto-fill, auto-fit 的例子,

.grid-container {
    display: grid;
    
    grid-template-columns: repeat(auto-fill, 100px);
    
    column-gap: 10px;
    
    width: 600px;
}
Gutter 在剩餘空間不足的情況

剩餘空間不足 的情況下,就會少了一個間隔,根據 w3c 官方 Grid gutters 的定義,在 Grid 容器尺寸無法放入更多的 Grid 單元,所以對於隱性軌道來說,他是一個空軌道,等同於 上一個 軌道是這個容器的最後一個軌道,所以在這邊的間隔並不會出現。

舉體來說 auto-fill, auto-fit 間隔的出現,可以用以下的方式解釋,

  • 剩餘空間不足,不出現最後一個間隔
  • 剩餘空間足夠,出現最後一個間隔

同理 auto-fit 也是一樣的狀況,以下的例子是當 剩餘空間足夠 時,你的間隔就會出現,

Gutter 在剩餘空間滿足時的情況

另外,官方雖然是這樣講,但實際上瀏覽器(除了 Firefox)並沒有這麼做,

When a collapsed track’s gutters collapse, they coincide exactly—the two gutters overlap so that their start and end edges coincide. If one side of a collapsed track does not have a gutter (e.g. if it is the first or last track of the implicit grid), then collapsing its gutters results in no gutter on either “side” of the collapsed track.

以下是 Webkit 渲染收合軌道時的情況,

Webkit 渲染收合軌道的問題

以下是 Grcko 渲染收合軌道的情況,

Gecko 渲染收合軌道的情況

個人覺得這是一種 Grid Layout 的 Bug,截至目前為止(2021/09/15),只有 Firefox 渲染引擎 Gecko 是比較正常的結果,有興趣的可以看這個小討論,

[css-grid] Collapsed grid tracks and content distribution #1140

最後稍微介紹一下 gap 的相關設定方式,

樣式 可用值 預設值
column-gap, row-gap normal 或長度單位或比例(%),不可為負值 normal
gap <'row-gap'> <'column-gap'>? 上述兩者縮寫,沒有預設值

最後的對齊

這件事情其實也是屬於 CSS Box Alignment Module 的部分,在 Flexbox 也通用,至於為何留到 Grid 才講?因為我覺得這個東西在 Grid 雷的程度比 Flexbox 要精彩許多。

在我們定義對齊的時候,有一組關鍵字可以使用,叫做 safeunsafe,他是用來定義你的對齊是否在 安全的範圍 內操作。

什麼叫做 安全的範圍

我們先舉個簡單的例子,當我這樣做的時候,你就會發現奇怪的現象,

.grid-container {
    display: grid;
    
    grid-auto-rows: 100px;
    
    align-items: center;
}

.grid-item:first-child {
    height: 200px;
}
在固定尺寸的 Grid 容器中,會發生對齊點超出容器的狀況

這個現象在 邏輯上 是合理的,由於 align-items 的本意是對齊每個 Grid 單元,然後使用了 center垂直置中 這個 Grid 單元。所以,他出現了 超出 Grid 容器 的狀況,根據邏輯定義上來說,他沒有問題。

但是,視覺上來看就是所謂的 跑版

所以,就有了所謂的 溢位定位(overflow position 的設定,就是剛剛提到的關鍵字,

  • safe 倘若對齊元件超過(產生溢位)對齊容器,則該元件會採用 start 方式對齊
  • unsafe 不採取任何動作,使用原有設定做呈現,由渲染端自己決定

預設是 unsafe 啦。所以不要太崩潰,如果發生溢位狀況的話,可能得先重新檢視一下網格設計是否合理,你硬要用 safe 也不是不行,只要達成你的效果即可。


小記

今天一個小段落就大家輕鬆一點,目前來說大抵上把 Grid 容器的部分都交代的差不多了,接下來可以開始講 Grid 單元,Grid 單元內巢狀 Grid 容器之類的事情,然後又是無限對齊、留白、定位等問題(燦笑)。


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


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