你如果會用 Excel,那 Grid 就應該不陌生。
不過老實講,我也不太會用 Excel。
Grid Layout Module
其實他已經 CR 好一陣子了,目前多數主流的 CSS 框架已經開始採用。所以並不是你不會用或是沒有使用到這個東西,而是你已經在用了,但是你不知道他背後是使用 Grid Layout 而已。
Grid 的基本結構就跟我剛剛提到的 Excel 很像,他是一個矩形區塊,包含了欄與列的設定。具體想要解決的問題在於「排版」這件事情,但試著回想這將近 20 年來排版的變化,是不是又很像回到了 <table>
的年代呢?
Grid 基本介紹
Grid Layout 基本上包含了下列結構:
- Grid 容器
- Grid 元件(或其子集合)
- 容器尺寸(寬度與高度)
相較之下,他沒有像是 Flexbox 有所謂的 軸方向 的問題。
基本的 Grid 容器組成就是這樣,看起來很簡單。由於沒有 Flexbox 的主要軸、交叉軸的問題,所以操作起來相對會比 Flexbox 容易一點點。
Grid 容器
首先,宣告一個 Grid 容器一樣是使用 display
屬性,
display: grid
亦即使用區塊(Box Level)來設定容器。display: inline-grid
亦即使用行內(Inline Level)來設定容器。
這裡跟 Flexbox 一樣,被定義出來的容器屬於 grid formatting context,所以原本在 Flexbox 上面會失效的事情,在這邊也一樣會失效。
float
,clear
會被忽略。vertical-align
無法應用在 Flex 元件上。::first-line
,::first-letter
這兩個擬似元件無法套用至容器上。
同樣的,倘若元素指定 display: inline-grid
的話,在計算樣式值(Computed Value)會呈現 grid
而不是 inline-grid
,這邊也是跟 Flexbox 一模一樣。
最大的不同點在於,Grid Layout 帶來了 格線軌道(Grid track)的概念。
一個 Grid 容器依據橫向(row)與縱向(column)來分割,這個分割的動作就是一個 格線軌道(Grid track)。這個軌道又可以區分為 網格單元(Grid cell)與 網格格線(Grid line)兩個面向。然後,網格單元與格線還可以區分出 命名單元(區域) 或 命名格線 的差異。
在這裡先有個底就好,後面會大量提及這些事情。
容器尺寸與限制
Grid 容器本身可以設定一定尺寸,但若不指定容器尺寸的情況下,Grid 容器尺寸會依照這些項目的總和來決定外部尺寸,
- 每一個格線軌道尺寸
- 包含間隔(gap)
- 每個軌道內容的最大(或最小)的內容尺寸(
min-content
或max-content
)
這樣會決定出 Grid 的最小或最大尺寸該是多少。通常在 軌道尺寸 夠用的情況下都不會有太大問題。問題在於不夠用的情況,倘若真的不夠用,就會採用軌道尺寸下的 min-content
來當作軌道尺寸,你的 Grid 容器尺寸設定基本上會無效。我後面會繼續舉例,這邊就先有個概念即可。
另外,倘若裝置對於網格有其限制,那麼在網格容器內的網格格線就會被限制。
- 當你的網格元件跨度(span)超出網格格線限制,則會被限制在最後一個網格軌道上。
- 當你的網格元件完全超出網格格線限制,則會被限制在最後一個網格軌道上,且網格軌道永遠為 1。
關於尺寸限制其實不太容易遇到,除非你故意的,或是你真的在一些比較特殊的顯示裝置要使用的時候,才必須留意這件事情。
網格單元與格線
在 Grid 容器當中,被 grid-template-rows
與 grid-template-columns
分割出來的區域,叫做網格單元(Grid cell),而這個容器單元會有所謂的格線,這個格線就是網格格線(Grid line)。
上圖用數字標出來的就是網格格線(Grid line),網格格線還有分成兩種:
- 一般網格格線(或命名網格格線)
- 隱性網格格線(implicit grid)
關於 Implicit Grid 我後面會介紹,如果你想看官方解釋也可以:
但我不保證看得懂。
容器樣式
這邊與 Flex 不同的點在於,他的樣式應用非常多,也相對複雜。
樣式 | 可用值 | 預設值 |
---|---|---|
grid-template-columns |
none , <軌跡清單> |
none |
grid-template-rows |
none , <軌跡清單> |
none |
grid-template-areas |
none , <字串> |
none |
grid-template |
上述三個設定的簡寫 | none |
grid-auto-columns |
<軌跡尺寸> |
auto |
grid-auto-rows |
<軌跡尺寸> |
auto |
grid-auto-flow |
row , column , dense |
row |
grid |
上述全部的簡寫 | none |
以上是一個 Grid 容器可以設定,關於容器本身的樣式。接著我們來看看裡面的設定值到底寫了些什麼東西。
軌跡清單
我們在設定網格的時候,比較常見的作法會類似這樣,
.grid-container {
display: grid;
grid-template-columns: 100px 500px;
grid-template-rows: 100px 100px 100px;
}
歐,你說我怎麼不用 fr
來當例子?這個新的單位後面會提到。這樣我們就可以擁有一個很簡單的網格容器,他包含了,
- 兩個欄(columns),寬度為
100px
與500px
- 三個行(_row),高度皆為
100px
這邊也可以搭 CSS 運算涵式或關鍵字使用,例如,
.grid-container {
grid-template-columns: 100px repeat(50px, 3) minmax(min-content, 1vw);
}
另外,前述有提到了網格格線(Grid line),在這邊可以替你的格線命名,預設在不命名的情況下,都是以 數字 來定義網格格線,
.grid-container {
grid-template-row: [first side-begin] 100px [side-ended main-begin] 100px [main-ended last];
}
格線名命名的規則就是用 []
把他包起來,這樣你的格線就會有一個特別的名字。另外請留意,不要用 -start
或 -end
來當作名稱,這樣的命名方式會踩到網格格線的雷。另外,名字可以一樣,但在指定的時候必須要特別指定你要在哪一個格線。
當你使用命名格線時,在指定網格單元時就可以使用名稱,而不是去計算數字,相對來說會比較方便一些。但如果你把網格格線的名稱都設定成同一個名字,那你在取用的時候還是要指定對應的數字才行。
但,都要你取名字了,盡量還是不要一樣比較好。
至於
-start
與-end
的雷,後續提到隱性網格會繼續講。
grid-template-areas
的字串定義
這個樣式的使用方式比較特別,他是需要定義每一個 網格單元 的名字,也就是說,我們可以寫成類似這樣,
.grid-container {
display: grid;
grid-template-areas:
"nav nav nav"
"sidebar main main"
"sidebar main main"
"sidebar main main";
}
所以,這個時候你的 HTML 就只會有三個元件,
<div class="grid-container">
<nav class="nav">
</nav>
<aside class="sidebar">
</aside>
<main class="main">
</main>
</div>
而這三個元件搭配的設定會是這樣,
.nav {
grid-area: nav;
}
.sidebar {
grid-area: sidebar;
}
.main {
grid-area: main;
}
最終你會得到這樣的結構,
當然,這種寫法不是沒有限制的,
- 命名規則組合必須要是矩形(N x M)
- 不同區塊不能使用重複名稱
- 可以用
.
來忽略(不使用)該區域 - 任何非預期字串都會被視為空白
所以說,以下的寫法 皆不合法,
/* 以下寫法不合法 */
.grid-container {
display: grid;
grid-template-areas:
"nav nav nav"
"sidebar main main"
"sidebar sidebar main"
"sidebar main main";
}
/* 以下寫法不合法 */
.grid-container {
display: grid;
grid-template-areas:
"nav nav nav"
"sidebar main main"
"sidebar . main"
"sidebar main main";
/* 以下寫法不合法 */
.grid-container {
display: grid;
grid-template-areas:
"nav nav nav"
"sidebar main main"
"sidebar main"
"sidebar main main";
}
另外,除了容器本身限制之外,當你的網格元件使用了 未命名 的網格單元時,會對隱性網格格線產生副作用。這個部分我後面會再次提及。
隱性網格
隱性網格(Implicit Grid)在網格系統中是一個很特別的存在。官方對他的說明簡單的解釋可以這麼形容,
你的設定不足以畫出一個網格,所以我
雞婆的幫你把缺的格線補上。
何謂設定不足以畫出網格?例如,
- 沒有設定欄(
grid-template-columns
)或列(grid-template-rows
) - 超出設定欄或列的數量
- 設定了
grid-area
卻不存在於grid-template-areas
當中
隱性網格有兩個樣式可以使用,
grid-auto-columns
grid-auto-rows
設定的數值僅接受這些,
auto
min-content
max-content
fr
minmax()
- 百分比單位數值(例如
10%
)
關於隱性網格在這邊就不贅述,後面會繼續提到這個東西。
網格單元順序
網格單元的順序其實跟 Flexbox 使用 order
的方式是一樣的,不過,他可以使用 z-index
來定義哪一個格子比較高。
通常會搭配 z-index
大多數是網格容器本身有捲動需求的時候會特別這樣做。
對齊與間隔
基本上網格容器的對齊跟 Flexbox 幾乎是完全一樣。我在這邊如果再講一次好像又太浪費篇幅。基本上以下這些東西跟 Flexbox 完全一樣,
align-items
align-self
align-content
justify-content
然後網格系統多了這幾個,僅能在 Grid 容器下使用,
justify-items
justify-self
place-items
place-self
place-content
間隔的部分也跟 Flexbox 使用同一套 gap
,其實就是共用同一套 w3c 的規範,
其實這邊沒有什麼新的東西,除了 Grid 才能使用的對齊方式外,其他的東西都跟 Flexbox 幾乎一樣。
justify-items
與 justify-self
是在容器系統中,Grid 單元主要軸向維度作對齊的樣式設定。與 align-items
, align-self
則是交叉向維度做對齊(或填充)的樣式。
Grid Layout 並沒有指定主要軸與交叉軸,這邊的軸向設定是跟著系統的文字流向而決定的。所以他沒有像是 Flexbox 可以明確的指定誰是主要軸,誰是交叉軸。
以下稍微說明一下 Grid 多出來的幾樣東西,
樣式 | 設定值 | 預設值 |
---|---|---|
justify-items |
normal , stretch , <baseline-position> , <overflow-position>? , [ <self-position>, left, right ] , legacy , `legacy && [ left |
right |
justify-self |
auto , normal , stretch , <baseline-position>, <overflow-position>? [ <self-position>, left, right ] |
auto |
place-items |
<'align-items'> <'justify-items'>? |
無特定預設值 |
place-self |
<'align-self'> <'justify-self'>? |
無特定預設值 |
place-content |
<'align-content'> <'justify-content'>? |
無特定預設值 |
基本上可以當作是在 Flexbox 上因為需要多行而無法特別設定的東西,在 Grid 裡面可以直接設定這樣的樣式。當然,如果你的 Grid 單元數量沒有到兩個欄或列以上,其實是看不出什麼效果的。
小記
今天先這樣,Grid 容器基本上東西太多,要一次講完有點困難。明天會搭配圖片來解說各種關於容器的設定,還有一些比較基本的運算方式。
目錄與小節:
[CSS] Flex/Grid Layout Modules, part 0