Skip to main content

[CSS] Grid Layout

Snippets#

/** * 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;
  /* 定義 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: span 3;  grid-row: span 2;
  /* width: 100% */  grid-column: 1 / -1;
  /* 套用 grid-area 的名稱*/  grid-area: foo;
  /* 對齊與置中 */  align-self: start | end | center | stretch(default);  justify-self: start | end | center | stretch(default);}

目錄#

[TOC]

參考#

重要觀念#

  • 當我們在定義 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:在 grid-template-columnsgrid-template-rows 中,若我們使用的是 % 作為單位時,它會以外層 container 的寬度當作總寬去計算百分比,但它不會把 grid-gap 的寬度考慮進去,因此使用 % 計算時,常常會超出整個 item 常常會超出整個 container 的寬度。這時候我們可以使用新的單位-fr,它會把 grid-gap 的寬度也算進去之後,剩餘的容器寬度下去做分配,分配的方式不是百分比,而是像 flex box 中的 flex-growflex-shrink 類似,按照每一個 item 所給的 fr 加以計算。
  • 容器高度:在預設 grid-auto-flow: row 的情況下,多出來的 grid-item 會自動換到下一行。這時候容器的高度或根據 item 的高度來自動延展,因此若使用 grid-template-rows 並搭配 fr 為單位時,有時候需要在 container 設定高度,才能有自動擴展的效果。

專有名詞(terms)#

名詞說明圖示
explicit track在 MDN 中稱為 explicit grid line,可以透過 grid-template-columngrid-template-rows 來定義。虛線(dashed line)
implicit track在 MDN 中稱為 implicit grid line,可以透過 grid-auto-rowsgrid-auto-columns 來定義。點線(dotted line)
gap在 MDN 中稱為 gutter 或 alleys,可以透過 column-gap, row-gap, 或簡寫的 gap 來定義。斜虛線(diagonal dashed line)
explicit grid edge實線(solid line)
grid track兩條線之間的區域。
grid cellgrid 的最小單位。
grid area多個 grid cell 可以組成 grid area,它一定是方形的,不會是 L 型的。

explicit 和 implicit grid track#

Explicit 和 implicit 的差別在於 explicit 是使用者透過 CSS 定義產生的,而 implicit 則是瀏覽器將剩餘的空間自行運用產生的:

  • explicit 的 grid 可以透過 grid-template-columnsgrid-template-rows 來定義,剩餘多出來的 grid 都視為 implicit grid。
  • implicit grid 預設的寬度會根據內容的大小來改變,若想改變 implicit grid 的話,可以透過 grid-auto-rowsgrid-auto-columns 來定義。

Imgur

grid-container#

定義 grid track 的欄寬和列高(grid-template-columns, grid-template-rows)#

  • px, rem:直接定義想要的值。
  • fr:fraction,指的是 container 扣掉 grid-gap 後的空間加以分配,用法類似 flex-growflex-shrink
  • auto:如果搭配的單位內有 fr 這類彈性變化的單位使用,則會以 grid-item 本身原本內容的寬度呈現;如果搭配的只有 pxrem 這類固定的單位,則會自動填滿所有剩餘的空間(見 [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 的 寬度和高度都相同時#

Imgur

當 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 填入,接著才考慮順序,最後放不下時才換行,較不易出現空白(但不保證一定沒空白),特別適合用在不那麼重視順序(例如,相片牆)的情況。

Imgur

對齊與置中(justify-content, justify-items, place-items)#

  • justify-content / align-content:用來對齊 grid-container 內的 grid-item,適用在以絕對單位定義寬度(例如,px),使得 grid-container 有多餘的空間時。
  • justify-items / align-items:用來對齊 grid-item 裡面的內容(content)。如果只要針對某個 grid-item ,可以針對該 item 下 align-selfjustify-self
  • place-items:是 align-items 和 justify-items 的縮寫,前者表示 align-items,後者為 justify-items,例如 place-items: centerplace-items: center start;
  • justify-xxx 適用於 x-axis;algin-xxx 適用於 y-axis。
  • 使用 align-content 時,最好幫 grid-container 設 height,且不要設定 grid-template-rows,效果會比較明顯(但是通常 grid-container 是不會設定 height 的)。
.grid-container {  justify-content: start | end | center | stretch(default) | space-around | space-between | space-evenly;
  justify-items: start | end | center | stretch(default);}

縮寫#

.grid-container {  grid: none | <grid-template-rows> / <grid-template-columns> | <grid-auto-flow> [<grid-auto-rows> [/ <grid-auto-columns>]];}
.grid-container {  grid: 200px auto / 1fr auto 1fr;}
/* 等同於 */.grid-container {  grid-template-rows: 200px auto;  grid-template-columns: 1fr auto 1fr;  grid-template-areas: none;}

grid-item#

定義要佔據多少欄或列(grid-column, grid-row)#

  • grid-column 可以用來定義該 item 要佔據幾個 column,預設是 grid-column: span 1
  • 當所設定的 grid-column 欄數過多而無法在該列容納下時,會自動換到下一行
  • 當所設定的 grid-column 欄數超過 grid-template-column 所設定的欄數時,會跑出新的 implicit grid column

使用 span <num> 可以用來定義要佔據幾個:

grid-column: span 2; /* 該 grid 會佔據 2 個欄寬 */

也可以透過 grid-column-startgrid-column-end 定義該 grid 要從第幾個 track 開始到第幾個 track 結束:

.grid-item {  /* short hand: grid-column: 3 / 5; */  grid-column-start: 3; /* 從 track 3 開始 */  grid-column-end: 5; /* 到 track 5 結束 */}

也可以同時使用 span <num>grid-column short hand

.grid-item {  /* 表示這個 grid-item 要佔據兩個欄寬,並以 track 5 的位置作為結束 */  grid-column: span 2 / 5;
  /* 表示這個 grid-item 要佔據三個欄寬,並以 track 2 的位置作為開始 */  grid-column: 2 / span 3;
  /* 表示這個 grid-item 要從,並以 track 2 的位置作為開始,track 5 的位置作為結束 */  grid-column: 2 / 5;
  /* 表示這個 grid-item 將佔據整個 row ,類似 width: 100% */  grid-column: 1 / -1;}

排序(order)#

使用 order 可以為 grid-item 重新排序,但要留意的是,沒使用 order 的 grid-item 會排在最面,接著才是有使用 order 的。另外,order 只是顯示時的順序改變,在瀏覽器的 DOM 並沒有真的改變它的位置,因此在

.grid-item {  order: 1;}

對齊與置中(justify-self, align-self)#

  • justify-self / align-self:用來針對單個 gird-item 中的 content 進行對齊。如果要改變所有 grid-items ,可以在 grid-container 中使用 align-itemsjustify-items
.grid-item {  align-self: start | end | center | stretch(default);  justify-self: start | end | center | stretch(default);}

grid function#

repeat(times, unit)#

grid-template-columns: repeat(4, 1fr); /* 1fr 1fr 1fr 1fr */grid-template-columns: repeat(2, 1fr 2fr); /* 1fr 2fr 1fr 2fr */grid-template-columns: 100px repeat(2, 1fr) 200px; /* 100px 1fr 1fr 200px */

auto-fill & auto-fit#

auto-fillauto-fit 都會自動根據 grid-container 的寬度調整欄數並換行,但是當 item 的數目不足以換行時,兩者的表現會有些微差異

  • auto-fill:當 grid-container 還有空間時,會繼續往後延伸新的 grid。
  • auto-fit:當 grid-container 還有空間時,不會繼續往後延伸新的 grid。
repeat(auto-fill, 100px)repeat(auto-fit, 100px)

Imgur

minmax()#

當我們做 RWD 時,常會希望 grid-item 中的項目可以隨著 container 自動延展,但卻又希望它的大小至少不要小於某一個值的時候,經常會使用到 minmax(min, max) 這個 function,第一個參數表示最小值,第二個參數表示最大值:

/** * 搭配 auto * minmax(100px, auto) 中的 auto 表示它會「根據內容的尺寸」來調整大小。**/.grid-container {  grid-template-columns: repeat(3, 1fr);  grid-auto-rows: minmax(100px, auto); /* 最小 100px,最大根據內容尺寸 */}
/** * 搭配 fr**/.grid-container {  grid-template-columns: repeat(3, 1fr);  grid-auto-rows: minmax(150px, fr); /* 最小 150px,否則大家分配相同的空間 */}

minmax() 經常搭配 auto-fitauto-fill 使用,做出不同的效果:

/** * 搭配 auto-fit 時,因為當 grid-container 還有空間時,不會繼續往後延伸新的 grid。 * 因此 grid-item 會根據 grid-container 的寬度佔滿整個 grid-container**/.grid-container {  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));}
/** * 搭配 auto-fill 時,因為當 grid-container 還有空間時,會繼續往後延伸新的 grid。 * 因此 grid-item 不會自動填滿整個 grid-container 的寬度,**/.grid-container {  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));}

Imgur

fit-content() 和 auto 的使用#

auto#

  • grid-template-columns 裡面的單位全都是絕對單位(例如, px ),則使用 auto 時該 gird-item 會自動延展 grid-container 中剩餘的空間。

  • grid-template-columns 裡面的單位有彈性單位(例如, fr ),則使用 auto 時該 gird-item 會根據 grid-item 的內容自動展開(不會讓 grid-item 換行)。

Imgur

fit-content()#

透過 fit-content 可以讓 grid-item 的內容一定不會超出 grid-item 的寬度(需要時會自動換行)

  • fit-content() 內給的值比 grid-item 中的內容寬小時,會自動換行,並縮小到可縮的最小寬度
  • fit-content() 內給的值比 grid-item 中的內容寬大時,效果會和有給 auto 和彈性長度時的效果一樣。

Imgur

其他#

為 grid track 命名:grid-template-areas & grid-area#

可以在 grid-container 中透過 grid-template-areas 定義每一個 grid-area (i.e., cell) 的名稱;接著可以在 grid-item 中選擇套用的 grid-area ,該 grid-item 會自動填滿所定義的 grid-area。

使用上可以類似 flex-box 中的 order,當在不同的裝置尺寸下時(搭配 @media),套用不同的 grid-template-area,即可重新定義整個 layout。

最好能先清楚透過 grid-template-columns 和 grid-template-rows 定義每個 grid-area。

/** * grid-template-areas 套用在 grid-container 上 * 透過雙引號包住一個 row * 如果有不想命名的 grid-area 可以使用 "." 代替**/.grid-container {  grid-template-columns: 1fr 500px 1fr;  grid-template-rows: 150px 150px 100px;  grid-template-areas:    'sidebar1 content sidebar2'    'sidebar1 content sidebar2'    'footer footer footer';}
/** * grid-area 套用在 grid-item 上 * 指定對應到的名稱後,該 grid-item 會填滿整個 grid-area**/.grid-item.sidebar1 {  grid-area: sidebar1;}.grid-item.sidebar2 {  grid-area: sidebar2;}.grid-item.content {  grid-area: content;}.grid-item.footer {  grid-area: footer;}

為 grid-area 命名後,也可以在 grid-item 中透過 xxx-startxxx-end 選擇它作為開始和結束的指標:

/* 可以直接在 grid-item 中使用定義好的名稱,不需加上雙引號 */.grid-item {  grid-column: foo-start / bar-end;}

為 grid-line 命名:grid-template-columns, grid-template-rows#

如果需要為 grid-line 命名,也可以在 grid-containergrid-template-columnsgrid-template-rows使用 [] 來定義 grid-line 的名稱,接著就可以直接在 grid-item 中的 grid-columngrid-row 使用。

/* 在 grid-container 中使用 [] 定義 track 名稱 */.grid-container {  display: grid;  grid-gap: 20px;  grid-template-columns: [site-left] 1fr [content-start] 500px [content-end] 1fr [site-right];  grid-template-rows: [content-top] repeat(3, auto) [content-bottom];}
/* 可以直接在 grid-item 中使用定義好的名稱,不需加上雙引號 */.grid-item.item3 {  background-color: steelblue;  grid-column: content-start / content-end;  grid-row: content-top / content-bottom;}

實際應用#

建立 Grid Layout#

.grid-container {  display: grid;  grid-gap: 20px;  grid-template-columns: repeat(10, 1fr); /* 建立每列有 10 個 column 的 grid */}
.grid-item {  grid-column: span 2; /* 定義該 item 要佔據幾個 column */}
.w-100 {  grid-column: 1 / -1; /* 該 item 會佔據整列 */}

參考#