【CSS】Grid 佈局總結

眼已望穿發表於2019-02-16

1. 前言

grid 佈局是 css 中的一種新的佈局方式,對盒子和盒子內容的位置及尺寸有很強的控制能力。與 flex 不同,flex 著重於單軸,而 grid 適應於多軸,下面就來做個簡單的介紹。

flex 佈局示意

【CSS】Grid 佈局總結

grid 佈局示意

【CSS】Grid 佈局總結

2. 基本概念

設定 display: grid; 的元素稱為容器,它的直接子元素稱為專案,但注意子孫元素不是專案。

grid line:網格線,構成 grid 佈局的結構,分為水平和豎直兩種。

grid track:兩條相鄰網格線之間的空間,可以認為是一行或者一列。

grid cell:兩條相鄰行和相鄰列之間分割線組成的空間,是 grid 佈局中的一個單元。

grid area:四條網格線包裹的全部空間,任意數量的 grid cell 組成一個 grid area。

3. 容器屬性

grid 容器的屬性還是有點多的,一共有 18 個,但是很多可以通過簡寫完成,所以也不用太緊張。

  • grid-template 系列
    • grid-template-columns
    • grid-template-rows
    • grid-template-areas
  • grid-gap 系列
    • grid-column-gap
    • grid-row-gap
  • place-items 系列
    • justify-items
    • align-items
  • place-content 系列
    • justify-content
    • align-content
  • grid 系列
    • grid-auto-columns
    • grid-auto-rows
    • grid-auto-flow

3.1 grid-template 系列

3.1.1 grid-template-columns 、grid-template-rows

定義行和列的數量。

.container {
  display: grid;
  width: 500px;
  height: 500px;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
}
複製程式碼

這樣就定義了一個三行三列的 grid 容器,grid-template-rows / grid-template-columns 接收的值有 auto、fr、px 和 %。

介紹一下 fr,其實也不難理解,類似 flex: 1 來就行了。

這裡可以給 grid line 命名,方便取到對應的 line 對 item 進行設定,詳情可以在下面 item 屬性上了解。

.container {
  display: grid;
  width: 500px;
  height: 500px;
  grid-template-columns: [column-1] 1fr [column-2] 1fr [column-3] 1fr [column-4];
  grid-template-rows: [row-1] 1fr [row-2] 1fr [row-3] 1fr [row-4];
}
/** 通過 repeat 方法可以簡寫如下
* 此處需要注意的就是線條命名變成了從1開始遞增,並且是用空格分隔字母和序號,類似: row 1、row 2、row 3
**/
.container {
  display: grid;
  width: 500px;
  height: 500px;
  grid-template-columns: repeat(3, 1fr column);
  grid-template-rows: repeat(3, 1fr row);
}
複製程式碼

【CSS】Grid 佈局總結

3.1.2 grid-template-areas

grid 模板區域:通過給網格區域指定名稱,方便專案屬性 grid-area 取用網格區域,句法如下: grid-template-areas: none | grid-area-name | .(半形句號);

none: 為定義的網格區域;

grid-area-name: 定義的網格區域名稱,專案屬性 grid-area 使用; .: 空的網格單元格;

.container {
  display: grid;
  width: 500px;
  height: 500px;
  grid-template-columns: repeat(3, 1fr column);
  grid-template-rows: repeat(3, 1fr row);
  grid-template-areas:
    "header header header"
    "main . sidebar"
    "footer footer footer";  
}
.container>div {
  border: 1px solid lightcoral;
}
// 專案
.item1 {
  grid-area: header;
}
.item2 {
  grid-area: sidebar;
}
.item3 {
  grid-area: main;
}
.item4 {
  grid-area: footer;
}
// html
<div class="container">
  <div class="item1">1</div>
  <div class="item2">2</div>
  <div class="item3">3</div>
  <div class="item4">4</div>
</div>
複製程式碼

最終效果圖如下:

【CSS】Grid 佈局總結

注意:當使用了 grid-template-areas 對網格命名後,網格的行、列的開始線與結束線會自動獲得一個 name-start、name-end 的命名,所以也會出現同一條線擁有多個名稱的情況,例如 header-start, main-start, and footer-start。

.item1 {
  grid-area: header;
}
// 以上程式碼效果等同於
.item1 {
  grid-column-start: header-start;
  grid-column-end: header-end;
}
複製程式碼

3.1.3 grid-template

終於到這個複合屬性了,該屬性類似 background、font、border 等,是對以上 grid-template 系列屬性的一個集合。

首先來看一下基礎語法: grid-template: none | grid-template-rows / grid-template-columns;

none: 將所有屬性重置為初始值;

grid-template-rows / grid-template-columns: 將 grid-template-columns 和 grid-template-rows 分別設定為指定值,並將 grid-template-areas 設定為none;

看到這可能有人會有疑問,說好的全部屬性呢,怎麼沒有看到 grid-template-area?實話說,句法有點複雜,下面單獨拎出來看看。

// 使用 grid-template 綜合之前的所有屬性
grid-template:
  [row1-start] "header header header" 1fr [row1-end]
  [row2-start] "main . sidebar" 1fr [row2-end]
  [row2-start] "footer footer footer" 1fr [row2-end]
  / [column-start] 1fr 1fr 1fr [column-end];

// -------------分割線-------------
.item1 {
  grid-column-start: header-start;
  grid-column-end: header-end;
}
// 以上程式碼效果等同於
.item1 {
  grid-column-start: column-start;
  grid-column-end: column-end;
}
複製程式碼

3.2 grid-gap 系列

這個系列比較簡單,就是定義行與行,列與列之間的間隙,就直接用 grid-gap 來介紹了。

grid-gap: grid-row-gap grid-column-gap; 如果只寫一個值那就是行、列間隙一致。

注意: 在 Chrome 68+, Safari 11.2 Release 50+ and Opera 54+ 以上版本中,可以去掉 grid 字首,而只需要些 row-gap、column-gap、gap 了。

.containner {
  // ... 之前的程式碼
  grid-gap: 10px;
}
複製程式碼

為了區分,用紅色框出來原來的佈局,虛線間的間隔就是設定的 10px 的 gap。 示意圖如下:

【CSS】Grid 佈局總結

3.3 place-items 與 place-content 系列

place-items: justify-items align-items;

place-content: justify-content align-content;

這兩個系列放在一起介紹,因為很多地方很相似,異曲同工。

justify-items: 網格項水平的對齊方式,預設是 stretch,其餘的值還有 start、end、center。

stretch:

【CSS】Grid 佈局總結

start:

【CSS】Grid 佈局總結

end:

【CSS】Grid 佈局總結

center:

【CSS】Grid 佈局總結

align-items:網格項垂直的對齊方式,整體如同 justify-items,不過水平換成了垂直。

// 下面兩個屬性需要我們調整一下之前的 css 程式碼,由於 place 系列需要某些特殊情況(就是 item 組成的網格大小小於容器)
.box {
  margin: 200px auto;
  display: grid;
  width: 500px;
  height: 500px;
  grid-template: 100px 100px / 100px 100px;
  gap: 10px;
  justify-content: start;
  border: 1px solid #ccc;
}

.box>div {
  border: 1px solid lightcoral;
}

.item1 {
  grid-column: 1;
  grid-row: 1;
}

.item2 {
  grid-column: 2;
  grid-row: 1;
}

.item3 {
  grid-column: 1;
  grid-row: 2;
}

.item4 {
  grid-column: 2;
  grid-row: 2;
}
複製程式碼

justify-content:網格整體相對於容器的水平對齊方式,預設值是 start,其餘的值還有 end、center、stretch、space-around、space-between、space-evenly。

start:

【CSS】Grid 佈局總結

end:

【CSS】Grid 佈局總結

center:

【CSS】Grid 佈局總結

stretch: 在這個例子中與 start 相同。

space-around:

【CSS】Grid 佈局總結

space-between:

【CSS】Grid 佈局總結

space-evenly:

【CSS】Grid 佈局總結

align-content:就是與 justify-content 相反的操作了。

3.4 grid 系列

grid-auto-columnsgrid-auto-rows 可以用來定義我們超出網格格數的隱式網格的大小。

.box {
  grid-auto-columns: 100px;
  grid-auto-rows: 100px;
}
複製程式碼

以上如果沒有定義 grid-template 之類的屬性的話,會根據 item 來生成 100 * 100 px 的網格。

.item4 {
  grid-column: 5 / 6;
  grid-row: 2 / 3;
}
複製程式碼

如果有一個這樣 item 定義超出了網格數,那麼它的大小就是 grid-auto 設定的 100 * 100 px,這裡要只能通過 grid-auto-columns 調整自動建立的 item 的寬度,高度不可以。

grid-auto-flow:定義了 item 的自流向方向,舉個例子。

// html
<div class="box">
  <div class="item1">1</div>
  <div class="item2">2</div>
  <div class="item3">3</div>
  <div class="item4">4</div>
</div>

// css
.box {
  margin: 200px auto;
  display: grid;
  width: 500px;
  height: 500px;
  grid-template: 1fr 1fr 1fr 1fr / 1fr 1fr;
  grid-auto-flow: row;
  gap: 10px;
  justify-content: start;
}

.box>div {
  border: 1px solid lightcoral;
}

.item1 {
  grid-column: 1 / 3;
  grid-row: 1;
}

.item4 {
  grid-column: 1 / 3;
  grid-row: 4;
}
複製程式碼

row 的情況:

【CSS】Grid 佈局總結

column 的情況:

【CSS】Grid 佈局總結

gird:是以下屬性的縮寫形式——grid-template-rows, grid-template-columns, grid-template-areas, grid-auto-rows, grid-auto-columns, 以及 grid-auto-flow。但是要注意的是,你只能同時宣告顯示屬性或者隱式屬性。

/** 
* 隱式屬性部分
**/
grid: auto-flow / 1fr 1fr 1fr;
// 等同於
grid-auto-flow: row;
grid-template-columns: 1fr 1fr 1fr;

grid: auto-flow dense 100px / 1fr 1fr 1fr;
// 等同於
grid-auto-flow: row dense;
grid-auto-rows: 100px;
grid-template-columns: 1fr 1fr 1fr;

/** 
* 顯示屬性部分
**/
gird: 1fr 1fr 1fr / 1fr 1fr 1fr;
// 等同於
grid-template-rows: 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;

/**
* 複雜屬性
**/
grid: [row1-start] "header header header" 1fr [row1-end]
      [row2-start] "main . sidebar" 1fr [row2-end]
      [row3-start] "footer footer footer" 1fr [row3-end] / 1fr 1fr 1fr;
// 等同於
grid-template-areas:
  "header header header"
  "footer footer footer";
grid-template-rows: [row1-start] 1fr [row1-end row2-start] 1fr [row2-end row3-start] 1fr [row3-end];
grid-template-columns: 1fr 1fr 1fr;
複製程式碼

4. 專案屬性

這裡有一個要注意的地方,flaot、display(inline-table、contents、 table 除外)、vertical-align 以及 column-* 對 grid item 專案無效。

4.1 grid-column、grid-row

旗下有 4 個屬性:grid-column-start、grid-column-end、grid-row-start、grid-row-end,用來確定 item 的位置。

屬性的值有:number | lineName | span <number> | span <lineName> | auto

對屬性的值以 9 宮格為例介紹。

number:從左往右從上往下分別是 1、2、3、4 四條。

lineName:在容器上定義的分隔線的名稱。

span <number> | span <lineName>:跨度的個數和跨到某條分隔線。

auto:自動跨度或預設 1 個跨度。

// 將某個 item 定位到 第 2 行第 3 列
// number
.item {
  grid-column: 3 / 4;
  grid-row: 2 / 3;
}
// lineName
.container {
  // ...
  grid-template-columns: [column-1] 1fr [column-2] 1fr [column-3] 1fr [column-4];
  grid-template-rows: [row-1] 1fr [row-2] 1fr [row-3] 1fr [row-4];
}
.item {
  grid-column:column-3 / column-4;
  grid-row: row-2 / row-3;
}
// span <number> | span <name>
.item {
  grid-column:column-3 / span 1;
  grid-row: row-2 / span row-3;
}
複製程式碼

4.2 grid-area

通過容器 grid-template-areas 設定的名稱設定 item 位置,也可以當做是 grid-row-start + grid-column-start + grid-row-end + grid-column-end 的縮寫。

.container {
  // ...
  grid: [row1-start] "header header header" 1fr [row1-end]
        [row2-start] "main . sidebar" 1fr [row2-end]
        [row3-start] "footer footer footer" 1fr [row3-end] / 1fr 1fr 1fr;
}
.item-1 {
  grid-area: header;
}
// 另一種寫法
.item {
  grid-area: row1-start / 1 / row1-end / 4;
}
複製程式碼

【CSS】Grid 佈局總結

4.3 place-self

旗下有 justify-self、align-self 兩個屬性:沿著內聯(行/列)軸對齊單元格內的網格項,主要的值有:start | end | center | stretch。

place-self: align-self justify-self;

.item-1 {
  place-self: center stretch;
}
複製程式碼

【CSS】Grid 佈局總結

5. 補充

顯式網格:通過使用 grid-template-columns 和 grid-template-rows 屬性顯式設定的一個網格的列和行。

隱式網格:grid-auto-flow 預設流,grid-auto-flow 屬性可以改變預設流方向 row 為 column。