相信大部分前端小夥伴已經有過使用 Grid 佈局的體驗,一定是美滋滋。Flex 佈局和 Grid 佈局作為 CSS 佈局領域的兩大新星,可謂是擁護者甚眾。我在前面這篇文章中總結了 Flex 佈局的強大之處,今天再來總結一下 Grid 佈局的基礎知識。
基本介紹
Grid 佈局在 2017 年開始已經逐漸獲得各大主流瀏覽器的支援,雖然暫時無法在生產環境中運用,但是它作為一項令所有 UI 工程師歡欣鼓舞的技術,是值得馬上去了解它的奧妙的。為了獲得更好的除錯體驗,我們可以在 FireFox 瀏覽器中學習它(FireFox 的開發者工具對它的支援很友好)。
那麼,它與傳統的佈局方案,包括前面介紹的 Flex 佈局方案相比的特性在於:
- 它是第一個真正意義上的佈局系統,其主要表現在它是第一個基於二維方向的佈局模組
- 它是第一個基於網格(或者叫柵格,本文叫網格)的原生布局系統
所謂基於二維方向,是指它可以針對水平和垂直方向兩個維度上進行佈局設計。在它之前,我們的佈局方案,只能在水平方向上進行佈局,對於垂直方向則無能為力,而 Grid 則可以輕鬆地實現二維佈局。
那麼,什麼是網格呢?我們可以這樣理解,網格是由一組水平和垂直的直線交叉,形成一個個矩形區域,我們可以將元素放置在這些區域中,這樣的好處是,元素可以很好地控制和對齊。
可以說,我們以前採取的佈局方案,其實是工程師們沒法子想出來的辦法,畢竟 position
,display
等屬性,並不是為了佈局而生的。而 CSS Grid,才是一個真正的佈局系統。
核心概念
瞭解了 CSS Grid 佈局的優越性,我們馬上來了解如何運用這項技術。
和 Flex 類似,Grid 的使用同樣簡單,第一步,我們需要把某個容器指定成網格容器:
.grid {
display: grid || inline-grid;
}
複製程式碼
這個時候,.grid
就變成了一個 網格容器(Grid Conatainer),包含在這個容器中的子元素則自動變成了 網格項(Grid Items), Grid 的所有屬性都在兩個概念之間展開。
下面這張圖,就是一個網格容器中,包含著 9 個網格項。
上面這個等寬的三行三列的佈局,如何實現呢?在傳統方案中,我們可能需要藉助浮動屬性等來實現,但是藉助 Grid ,就很簡單了,在為父元素指定 display: grid;
之後,我們可以藉助兩個屬性: grid-template-columns
, grid-template-rows
和一個新單位 fr
來輕鬆實現。
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
grid-gap: 20px 10px;
}
複製程式碼
grid-template-columns
和 grid-template-rows
分別表示水平方向上和垂直方向上網格項的空間分配比例,fr
是一個新單位,表示佔據可用空間的一等分。所以上面的程式碼表示,在水平和垂直方向分別把可用空間分為三份,且三份佔據空間相等。grid-gap
屬性指的是網格項之間的間隙,後面會介紹到。
學習到了這兩個屬性,我們已經可以輕鬆地佈局出常見的多欄佈局,例如我們要實現一個水平為 1:2:1 的佈局,可以這樣實現:
.grid {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-gap: 10px;
}
複製程式碼
當然我們同樣可以為上面的屬性設定固定的長度,例如畫素值。
Grid 佈局為我們提供一個 repeat()
函式來更高效地實現複雜的佈局,它可以接收兩個值,第一個值是重複的數量,第二個值是重複的模式,例如:repeat(3, 1fr)
表示三等分的佈局,repeat(3, 1fr 200px)
表示把1fr 加一個200px的佈局重複三次。
以上的賦值形式可以混雜來使用,例如:
grid-template-columns: 200px 1fr repeat(3, 100px);
複製程式碼
上面的佈局從左到右呈現為:200px 1fr 100px 100px 100px.
grid-auto-columns
grid-auto-rows
在我們沒有顯示地藉助前面的 grid-template-columns
和 grid-template-rows
來指定網格項的空間分配方式的時候,我們可以使用 grid-auto-columns
和 grid-auto-rows
兩個屬性來設定網格區域的自動顯示範圍,經常可以藉助一個工具函式 minmax()
來指定,例如 grid-auto-rows: minmax(120px, auto)
,表示不管網格區域中有沒有內容,其高度最小為 120px,如果其有超過 120px 的部分的內容,則自動擴張。
網格線(Grid Line)
所謂網格線,就是兩個網格軌道之間以及網格邊緣的直線,在上面這個三行三列的網格中,水平和豎直方向上各有四條網格線,在 Grid 中,我們通常按照書寫方向,為這些網格線編號,水平方向上,我們從左至右,將它們編號為 “1, 2, 3, 4···”,豎直方向上同理,從上往下編號,如下圖所示:
網格軌道(Grid Track)
網格軌道指的是任意兩條網格線之間的空間(這條線不一定看得見),在上面的圖片中,我們可以清晰地看到水平和豎直方向上黑線之間的網格軌道,而我們的網格項就是在這些軌道上安放。
網格區域(Grid Area)
網格區域,就是若干個相鄰的網格單元組成的區域,我們可以通過組合網格單元來建立出不同大小的網格區域。
下面為了不致混亂,我們分網格容器和網格項來說明它們上面可以設定的屬性。
網格容器上可以設定的屬性有(因為二維佈局,基本來說,某一個針對水平方向的屬性,同樣有一個數值方向的屬性與之相對應,為了方便,我們一起介紹它們):
display: grid || inline-grid || subgrid
grid-template-columns
和grid-template-rows
grid-auto-columns
和grid-auto-rows
grid-auto-flow
grid-column-gap
和grid-row-gap
以及兩者合寫grid-gap
justify-items
align-items
justify-content
align-content
grid-template-area
網格項上面可以設定的屬性有:
grid-column-start
grid-column-end
grid-row-start
grid-row-end
grid-column
(1 和 2 的合寫形式)gird-row
(3 和 4 的合寫形式)grid-area
justify-self
align-self
別看上面的屬性很多,其實讀者完全不必慌,一則是這些屬性中高頻使用的就幾個,二者是上面好幾組屬性完全可以用它們的縮寫形式來替代。下面來介紹其中高頻使用的一些屬性(更詳細的大家可以在 MDN 上檢視詳情介紹),前面已經瞭解的部分不再贅述。
grid-gap
grid-gap
用來設定網格間距,也就是兩個網格之間留出來的空白,其可以在橫向和縱向分別通過 grid-column-gap
和 grid-row-gap
來設定相應的大小,這兩個屬性值通常可以合寫為 grid-gap
:
.grid {
grid-gap: 20px 10px;
}
複製程式碼
在橫向設定 10px 的間距,縱向設定 20px 的間距,如果,橫向和縱向要設定的大小一致時,可以直接縮寫為一個值: grid-gap: 20px;
我們可以從這張圖上看到這些概念。
grid-template-areas
這個屬性十分方便,可以通過指定網格單元的名字來定義一個網格模板,然後在網格項上面使用 grid-area
屬性與之配合,來確定其顯示的區域。重複相同的網格單元的名字,就會自動合併兩個單元,可以使用一個句點 .
來表示一個空白的網格單元。例如以下的一個佈局形式:
程式碼:
.grid {
display: grid;
grid-gap: 10px;
grid-template-columns: 1fr 1fr 1fr;
grid-template-areas: "header header header"
"siderbar content content"
"footer footer footer"
}
.one {
grid-area: header;
}
.two {
grid-area: siderbar;
}
.three {
grid-area: content;
}
.four {
grid-area: footer;
}
複製程式碼
通過例項我們可以看到,在網格容器上,我們為其定義網格區域的顯示模板,然後在相應的網格項上將設定好的 grid-area-name 賦值給 grid-area
屬性,這樣就可以很便捷地達到我們的效果。
justify-items
和 align-items
我們知道在 Flex 佈局中,可以藉助 justify-content
以及 align-items
來設定彈性專案在水平和豎直方向的對齊方式,強大的 Grid 系統自然也可以進行設定,其屬性和 Flex 很相似,分別使用 justify-items
和 align-items
(後者和 Flex 一致有沒有)。不同的是,這兩個屬性的屬性值是參照網格線來確定它們的位置:
.grid {
justify-items: start | end | center | stretch;
}
複製程式碼
屬性值介紹:
- stretch: 預設值,內容充滿整個網格區域
- start:網格項內容與網格區域左側對齊
- end: 網格項內容與網格區域右側對齊
- center: 網格項內容在網格區域居中顯示
align-items
與前者相同道理,不再贅述。如果在前面的例子中,我們將這兩個屬性值設定為 center
, 則它們就會呈現為下面這幅樣子:
gird-column
和 grid-row
除了在網格容器上統一進行的設定,我們可以針對特定的網格項進行設定,決定其佔據的網格區域,我們可以藉助網格線的約束,來決定某一個網格項的空間。例如,我們想要實現一個元素佔據水平方向從第 1 條網格線到第 3 條網格線,豎直方向從第 2 條網格線到第 4 條網格線,也就是下面紅色元素的位置:
如何實現呢,水平方向藉助這兩個屬性:grid-column-start
, grid-column-end
,分別表示該網格項開始和結束的網格線序號,其值是代表網格線的編號。
.item1 {
grid-column-start: 1;
grid-column-end: 3
}
複製程式碼
豎直方向同理,使用 grid-row-start
和 grid-row-end
兩個屬性實現:
.item1 {
grid-row-start: 2;
grid-row-end: 4;
}
複製程式碼
如此一來,就可以實現上面圖中的效果,這兩組屬性同樣有相應的縮寫形式,我們把 grid-column-start
, grid-column-end
合寫為 grid-column
,把 grid-row-start
和 grid-row-end
合寫為 grid-row
,其值用一個 /
來分隔。
grid-column: 1/3;
grid-row: 2/4;
複製程式碼
justify-self
和 align-self
這兩個屬性用來設定特定網格專案在其網格區域中的對齊方式,其可取的屬性值與 justify-items
和 align-items
相同。不再說明。
更改重疊區域的層級順序
當兩個網格區域在空間上發生重疊之時,其層疊順序按照其在 DOM 結構中的出現前後決定,後來者會居上。如果我們想人為改變這些重疊次序,可以為相應的區域設定 z-index
屬性,來改變它的層疊優先順序,這和定位元素的設定一致。
以上就是 Grid 佈局的基本概念,我們可以看到,最常用的幾個屬性是:grid-template-*
相關的幾個屬性,用來指定網格區域留白的 grid-gap
,以及用來宣告網格專案在各自網格區域中的對齊方式的 align-items
以及 justify-items
兩個屬性。在網格項上,用來指定網格項顯示區域的 grid-column
以及 grid-row
屬性,指定特定網格項在其網格區域中對齊方式的 align-self
和 justify-self
屬性。用熟了這些屬性,Grid 佈局的使用自然是手到擒來,至於其它更復雜的屬性,在後來的學習中循序漸進使用並熟悉。文中有什麼疏漏和錯誤之處,希望大家指正。