[CSS] Grid Layout
TL;DR
- grid 和 flexbox 有一個關鍵的差異是,grid 需要用 2D 的角度來思考畫面的排版。
Snippets
- Less Absolute Positioning With Modern CSS:透過 CSS Grid 不用使用 position absolute,並做出常見的樣式。
/**
* Responsive Tiles
*/
.grid-container {
// 使用 auto-fill 讓它自動決定一行要有幾個 columns
// 使用 minmax,使得 grid-item 最小至少要 300px,最大則會自己延伸
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
grid-auto-rows: 1fr; // 如果需要讓所有的 gird-item 等高
}
See the Pen Grid Image Tile Layout by PJCHEN (@PJCHENder) on CodePen.
常用屬性
.container {
display: grid;
/* 定義 grid 之間的間距 */
grid-row-gap: 10px;
grid-column-gap: 20px;
grid-gap: <grid-row-gap> <grid-column-gap>;
/* 定義 explicit track */
grid-template-columns: 100px auto 5rem;
grid-template-rows: 200px 10px;
// grid-template 是 grid-template-rows / grid-template-columns 的縮寫
grid-template: repeat(3, 1fr) / repeat(2, 1fr);
/* 定義 implicit track */
grid-auto-rows: 500px;
grid-auto-columns: 300px;
/* 定義多餘的元素要以什麼方式排列 */
grid-auto-flow: column | row(default) | dense;
/* 定義 grid-area 的名稱 */
grid-template-areas: 'foo bar';
/* 對齊與置中 */
/*
start | end | center |
baseline | first baseline | last baseline |
flex-start | flex-end | left | right |
space-between | space-around | space-evenly |
stretch(default);
*/
align-items: baseline | stretch(default); // no left, right
justify-content: left | right | stretch(default); // no baseline
align-content: start | end | center | stretch(default);
place-content: <align-content> <justify-content>;
/* repeat (times, unit) */
grid-template-columns: repeat(4, 1fr); /* 1fr 1fr 1fr 1fr */
/* minmax 搭配 auto-fit */
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.grid-item {
/* 定義該 item 要佔據幾個 column 或 row */
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 3;
// grid-column 是 grid-column-start / grid-column-end 的縮寫
grid-column: 2 / span 2; // 從 column 2 開始算起,佔據 2 個 column
grid-column: span 3; // 從現在的位置算起,佔據 3 個 column
grid-column: 1 / 3; // 從 column 1 開始到 column 3
grid-column: 1 / -1; // width: 100%
grid-row: span 2; // 從現在的位置算起,佔據 2 個 row
// row-start / column-start / row-end / column-end
grid-area: 1; // 等同於 1/auto/auto/auto
grid-area: 1 / 1 / 2 / 3;
/* 套用 grid-area 的名稱*/
grid-area: foo;
/* 對齊與置中 */
align-self: start | end | center | stretch(default);
justify-self: start | end | center | stretch(default);
}
目錄
[TOC]
參考
- Get Started with Grid Layout @ Grid by Example
- A Complete Guide to Grid @ CSS Tricks
- CSS Grid @ Wes Bos
- CSS Grid Layout Guides @ MDN - Web technology for developers
重要觀念
- 當我們在定義 grid 的時候,是透過定義 grid track (grid cell) 來達到,而不是透過定義 grid-line。但是當我們要放置 grid-item 的時候,則是透過 grid line,而非 grid track。
- grid-auto-flow:預設的情況下,當我們只定義兩欄,但卻有超過兩個 grid-item 時,多出來的 grid-item 會自動換到下一列,這時候我們可以使用
grid-auto-flow: column
調整成不換行。 - 使用單位 fr (fraction):在
grid-template-columns
或grid-template-rows
中,若我們使用的是 % 作為單位時,它會以外層 container 的寬度當作總寬去計算百分比,但它不會把grid-gap
的寬度考慮進去,因此使用 % 計算時,常常會超出整個 container 的寬度。這時候我們可以使用新的單位-fr,它會把grid-gap
的寬度也算進去之後,剩餘的容器寬度下去做分配,分配的方式不是百分比,而是像 flex box 中的flex-grow
和flex-shrink
類似,按照每一個 item 所給的fr
加以計算。 - 容器高度:在預設
grid-auto-flow: row
的情況下,多出來的 grid-item 會自動換到下一行。這時候容器的高度或根據 item 的高度來自動延展,因此若使用grid-template-rows
並搭配 fr 為單位時,有時候需要在 container 設定高度,才能有自動擴展的效果。
專有名詞(terms)
名詞 | 說明 | 圖示 |
---|---|---|
explicit track | 在 MDN 中稱為 explicit grid line,可以透過 grid-template-column 和 grid-template-rows 來定義。 | 虛線(dashed line) |
implicit track | 在 MDN 中稱為 implicit grid line,可以透過 grid-auto-rows 和 grid-auto-columns 來定義。 | 點線(dotted line) |
gap | 在 MDN 中稱為 gutter 或 alleys,可以透過 column-gap , row-gap , 或簡寫的 gap 來定義。 | 斜虛線(diagonal dashed line) |
explicit grid edge | 實線(solid line) | |
grid track | 兩條線之間的區域。 | |
grid cell | grid 的最小單位。 | |
grid area | 多個 grid cell 可以組成 grid area,它一定是方形的,不會是 L 型的。 |
explicit 和 implicit grid track
Explicit 和 implicit 的差別在於 explicit 是使用者透過 CSS 定義產生的,而 implicit 則是瀏覽器將剩餘的空間自行運用產生的:
- explicit 的 grid 可以透過
grid-template-columns
和grid-template-rows
來定義,剩餘多出來的 grid 都視為 implicit grid。 - implicit grid 預設的寬度會根據內容的大小來改變,若想改變 implicit grid 的話,可以透過
grid-auto-rows
和grid-auto-columns
來定義。
grid-container
定義 grid track 的欄寬和列高(grid-template-columns, grid-template-rows)
px
,rem
:直接定義想要的值。fr
:fraction,指的是 container 扣掉 grid-gap 後的空間加以分配,用法類似flex-grow
和flex-shrink
。auto
:如果搭配的單位內有fr
這類彈性變化的單位使用,則會以 grid-item 本身原本內容的寬度呈現;如果搭配的只有px
或rem
這類固定的單位,則會自動填滿所有剩餘的空間(見 [fit-content() 和 auto 的使用](#fit-content() 和 auto 的使用))。
.grid-container {
grid-template: <grid-template-rows> / <grid-template-columns>; /* 縮寫 */
grid-template-columns: auto 50px auto;
grid-template-rows: 10px 10px 10px;
}
定義 grid item 間距的寬度(grid-gap)
.grid-container {
grid-gap: <grid-row-gap> <grid-column-gap>; /* 縮寫 */
grid-row-gap: 20px;
grid-column-gap: 20px;
}
定義 grid item 排列的方式(grid-auto-flow)
.grid-container {
grid-auto-flow: row(default) / column / dense;
}
當每一個 grid 的 寬度和高度都相同時
當 grid 的寬高有所不同時
.grid-container {
display: grid;
grid-gap: 20px;
grid-auto-flow: dense;
grid-template-columns: repeat(10, 1fr);
}
.grid-item:nth-child(3n) {
background-color: cornflowerblue;
grid-column: span 5;
}
.grid-item:nth-child(5n) {
background-color: tomato;
grid-column: span 4;
}
.grid-item:nth-child(7n) {
background-color: greenyellow;
grid-row: span 2;
}
- 使用預設的
grid-auto-flow: row;
則不考慮 grid-item 的大小,僅依照順序將 grid-item 填入,但若放不進去,則會換行,因此較容易留有空白。 - 使用
grid-auto-flow: dense;
則會先盡可能依照大小把可以放入的 grid-item 填入,接著才考慮順序,最後放不下時才換行,較不易出現空白(但不保證一定沒空白),特別適合用在不那麼重視順序(例如,相片牆)的情況。