Grid 佈局又叫做網格佈局,顧名思義是一種基於二維網格的佈局方式,Grid 的強大令人興奮,讓我們一起來走進 Grid 的世界吧。
相容性
好了,大家都坐好,我準備發車啦。不符合要求的同學請下車,沒滿 18 歲的,咳咳,開玩笑。不是所有人現在都能搭上 Grid 的小車車,畢竟專案相容性問題很現實,不過不耽誤我們學習。
我替大家翻譯一下上面的瀏覽器都是啥,順序從左到右:
- PC 端: Chrome、Edge、Firefox、IE、Opera、Safari
- 移動端: Android、Chrome for Android、Edge Mobile、Firefox for Android、Opera、IOS Safari、Samsung Internet
好了,大家看了看瀏覽器的相容性就知道,如今主流瀏覽器都已經支援了 Grid 佈局,還等啥呢?上車吧。
基本概念
乘客們,在開始瞭解用法之前,我們要了解一些 Grid 佈局的基本概念,我想大家應該小時候都用過一種叫小字本的東西,這就是個正兒八經的網格。
- Container: 網格容器,當我們設定
display: grid;
就將一個容器變成了網格容器,就比如說上面小字本里外層的那個綠框。 - Item: 網格項,在我們設定的網格容器中的每一個子元素都是網格項。
- Line: 網格線,顧名思義啦,這東西就是網格之間分界的線,就上小字本里的橫著豎著的線。
- Track: 網格軌道,兩條相鄰的網格線之間的空間,也就是網格的行或列。
- Cell: 網格單元,兩個相鄰的行和列之間的區域,也就像是小字本里的每個小格子了。
- Area: 網格區域,四條網格線包圍起來的區域。
好了,基本概念瞭解的差不多了,我們去往下一站。
基本用法
第二站到了,我們要繼續吹牛了。
本站要介紹的 api:
grid-template-columns
和grid-template-rows
grid-gap
->grid-row-gap
+grid-column-gap
第一件事,掏出程式碼:
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
複製程式碼
body {
background: #CCCCCC;
}
.container > div {
font-size: 35px;
font-weight: bold;
color: #fff;
text-align: center;
background: #666666;
}
.container > div:nth-child(2n) {
background: #336666;
}
.container > div:nth-child(4n) {
background: #f37e70;
}
.container {
display: grid;
grid-template-columns: 120px 120px 120px;
grid-template-rows: 50px 50px;
}
複製程式碼
好了,現在它長這個樣子。
我們可以看出上面一些關鍵的 css 程式碼:
- 使用
display: grid;
將外層容器變成一個網格佈局容器。 - 現在我們擁有了一個容器,我們現在要開始幹什麼了?對,沒錯,我們要開始把這個容器畫成一個一個的格子。
grid-template-columns: 120px 120px 120px;
將容器畫成 3 列,每列 120px;grid-template-rows: 50px 50px;
畫成 2 行,每行 50px。
上面兩個 api 給網格加上了兩條橫線,三條豎線,把容器畫成了一個個的格子。然後將網格項一個一個填進去,那麼聰明的同學又會想了,你這樣畫好格子,裡面有 6 個格子,那我再添一個 div 會出現什麼情況?好吧,滿足這位同學的好奇心,我們加一個 div 進去。
然後就會變成這樣:
神奇,是不是,明明俺就畫了 6 個格子,居然 7 出現了,並且還有一定高度。其實在 grid 裡,它有一個隱式網格軌道。
當我們的網格項處於我們沒有定義的網格部分的時候,它會有一個預設的值,我們也可以選擇去定義隱式網格軌道的大小,通過 grid-auto-rows
和 grid-auto-columns
來定義行和列,關於這部分要說的話很多,大家可以到這個部落格去了解。
講完這個,我們再看看,每個格子捱得太近了,一點都不美觀,咋辦呢?我們加上 grid-gap: 2px 4px;
看看:
可以看到,使用這個屬性我們定了網格的間隙,這個 api 其實是兩個 api 的組合(grid-column-gap
和 grid-row-gap
)。
好了,這一站就是基本用法,下面我們繼續發車啦。
fr 單位以及 repeat
上面我們通過一些基礎的屬性,寫了一個 6 個格子的頁面。這一節我們不講屬性,講一下在 grid 中的一個單位值 — fr。那麼這個 fr,代表的是什麼意思呢?在 flex 中也有類似的屬性,fr 的意思就是在自由空間進行分配的一個單位,那麼是什麼意思呢?
比如說,容器寬度為 1000px,現在假如 grid-template-columns: 200px 1fr 1fr 2fr
。那麼這就表示分了 4 列,第一列為 200px,然後剩下的 800px 就是自由空間了,經過計算可以得出 1fr 為 200px,這就是 fr 的意義。
那麼,我們上面的例子其實可以這樣寫 grid-template-columns: 1fr 1fr 1fr;
。但是現在又出現了一個問題,這個 1fr 寫的好煩,能不能就寫一個。
好訊息,是有的,我們可以使用 repeat 來簡寫,於是上面的例子又可以改成 grid-template-columns: repeat(3, 1fr)
。
說完這兩個,我們繼續下一站。
網格線的應用
這一站我們要說這些 api:
grid-column
->grid-column-start
+grid-column-end
grid-row
->grid-row-start
+grid-row-end
好了我們拋棄上面的例子,現在假如我們接到一個需求,我們要使用 3 欄佈局,左右固定 200px,中間自適應,咋辦呢?相信大家一下就想到了,畢竟大家都很聰明。
<div class="container">
<div>Left</div>
<div>Main</div>
<div>Right</div>
</div>
複製程式碼
// ...,跟上面相同的程式碼
.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 500px;
grid-gap: 2px 4px;
}
複製程式碼
好了,現在我們是這樣的:
需求又來了,我們要加上一個 header 和一個 footer,寬度是 main 的寬度,現在又怎麼辦呢?首先 container 需要改:
.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 100px 500px 100px;
grid-gap: 2px 4px;
}
複製程式碼
現在我們可以用網格線來進行佈局了,在上面的網格佈局中橫向有 4 條網格線,豎向有 4 條網格線,預設網格會為編號,從 1 開始,於是我們可以用網格線將元素固定到它應該在的位置:
/* 類名就是 html 對應的 div */
.left {
grid-column: 1 / 2;
}
.main {
grid-column: 2 / -2;
}
.right {
grid-column: -2 / -1;
}
.header {
grid-column: 2 / -2;
}
.footer {
grid-column: 2 / -2;
}
複製程式碼
這樣的話,我們的佈局就成了這樣子:
在上面有一個小技巧,如果中間線比較多,你要選擇比較靠後的線,就可以使用負數來進行選擇。
上面的 1 和 2 的使用是差不多的,這裡就不詳述了。
注意,你可以給網格線取一些語義化的名字便於你使用,比如下面這樣,footer 一樣可以和 main 等寬:
<div class="container">
<div class="left">Left</div>
<div class="main">Main</div>
<div class="right">Right</div>
<div class="footer">Footer</div>
</div>
複製程式碼
.container {
display: grid;
grid-template-columns: 200px [main-start] 1fr [main-end] 200px;
grid-template-rows: 200px 200px;
grid-gap: 2px 4px;
}
.footer {
grid-column: main-start / main-end;
}
複製程式碼
我們可以給網格線取名字,然後再去使用它。
網格區域應用
這節介紹的 api:
- grid-template-areas
- grid-area
我們可以通過另一種建立網格的方式來定位元素,就如同畫圖一樣,就那上面那個有 header 和 footer 的例子來說,我們可以這麼寫:
.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 50px 300px 50px;
grid-template-areas:
". h ."
"l m r"
". f .";
grid-gap: 2px 4px;
}
.header {
grid-area: h;
}
.left {
grid-area: l;
}
.right {
grid-area: r;
}
.main {
grid-area: m;
}
.footer {
grid-area: f;
}
複製程式碼
通過這樣的方式,我們一樣能做到上面的那種定位操作,注意的是在 grid-template-areas
中 . 代表的是這個位置空著。
repeat 進階
在上面,我們說過一種 repeat 的簡單用法,建立網格時重複指定的次數,但是有的時候我們並不想指定次數,而是希望自動填充,這時候怎麼辦呢?
這時候我們就要提到 auto-fit
和 auto-fill
了。
首先,我們通過 repeat 先把格子建出來:
.container {
display: grid;
grid-template-columns: repeat(9, 1fr);
grid-template-rows: 50px;
grid-gap: 2px 4px;
}
複製程式碼
這樣我們就建立了一個基於 9 列的網格系統,如果我們的視窗不斷變小,那麼我們的每一格也會相應的變窄,我們不希望它變得非常窄,咋辦呢?
Grid 有一個 minmax() 函式可以使用,這個函式接收兩個引數,一個最小值,一個最大值,當瀏覽器視窗發生改變的時候,它能夠保證該元素是在這個範圍之內改變。比如說:
.container{
grid-template-columns: repeat(9, minmax(250px, 1fr));
}
複製程式碼
當我們把 grid-template-columns
變成這樣之後,每一列的寬度都會在 250px 到 1fr 之間,但是我們會發現,他裝不下這些格子,但是它也沒有換行,因為你告訴它有 9 列,於是出現了滾動條,但是你不希望出現這東西,咋辦呢?
這時候就到了我們上面說的兩個引數出場的時候到了。
.container{
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
複製程式碼
當我們加上這個引數過後,就會讓瀏覽器去處理列寬和換行的問題,如果你給的容器寬度不夠,它就會換行。
那麼 fit 和 fill 有啥區別呢?我找了一些資料,裡面有兩句總結是這麼說的:
auto-fill
傾向於容納更多的列,所以如果在滿足寬度限制的前提下還有空間能容納新列,那麼它會暗中建立一些列來填充當前行。即使建立出來的列沒有任何內容,但實際上還是佔據了行的空間。
auto-fit
傾向於使用最少列數佔滿當前行空間,瀏覽器先是和 auto-fill 一樣,暗中建立一些列來填充多出來的行空間,然後坍縮(collapse)這些列以便騰出空間讓其餘列擴張。
做一個實驗,當寬度足夠大時,這兩者區別就出來了:
.container1{
grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
}
.container2{
grid-template-columns: repeat(auto-fit, minmax(40px, 1fr));
}
複製程式碼
這樣可以看出區別了,fill 是儘可能多容納列,它會自己造一些列來填充剩餘空間,其實它是鋪滿了的,只是你看不見而已,而 fit 是擴張原有列來鋪滿這一行。
至於具體詳細的解釋,大家可以去這篇譯文看一看,說得非常詳細了。
總結
好了,關於 grid 大概就說這麼多了,其實關於這些 api 的使用還有很多的引數問題,這裡沒有細說,只是讓大家知道 grid 能幹嘛,至於詳細的說明,可以去下面幾個部落格看一看。
另外還有一些屬性沒有介紹,是關於對齊等屬性,大家在有需求的時候可以去下面的資料找到。
更多資料:
如果各位看官看的還行,可以到 我的部落格倉庫 裡給我一顆小小的 star 支援一下,不勝感激。