圖解CSS網格

寫在前面的話

本文爲譯文,由於筆者也是最近開始嘗試翻譯文章,若有翻譯地不合理或者不正確的地方,歡迎指出。原文地址:CSS Grid: illustrated introductioncss

正文開始

我還記得第一次學習CSS知識的時候,我是如何興奮地學習使用float和inline展現元素在想要的佈局位置。我想知道若是當時有一個二維佈局系統,我會做何反應。事實上,即便到如今我仍是感到興奮,由於咱們編寫CSS的方式以及咱們編寫標記語言的方式改變了一切。使用CSS網格,使得咱們構建響應式的、動態的、源碼順序獨立的佈局比以前更加容易。html

注意,源碼順序獨立只是根據字面翻譯,我理解的含義是編寫的html標籤的順序跟頁面上展現標籤的順序無關,咱們能夠經過CSS 網格樣式任意修改元素在頁面上的展現順序。算法

在本文中,咱們將學習使用全部的CSS網格知識來構建簡單的和一些不太容易的佈局。咱們將定義一切CSS網格知識,而後接着將挖掘得更深一點,看看咱們可使用CSS網格實現什麼樣的佈局。話雖如此,若是你已經準備好學習一種新的佈局方式,吃下紅色藥丸,我會告訴你兔子洞到底有多深。編程

matrix red pill choice

1.在咱們開始以前

在咱們開始學習以前,我想提出一些或許你也可能有的一些顧慮,同時確保咱們熟悉CSS網格的基礎知識和術語。瀏覽器

Q & A

Q:CSS網格會替代flex-box佈局嗎?框架

A:固然,CSS網格不會替代flex-box,這兩種佈局是針對不一樣的使用場景。事實上,它們還能夠很好地搭配使用。咱們能夠在CSS網格佈局中使用flex佈局,反之亦然。函數

Q:CSS網格佈局和flex-box佈局有什麼不一樣?佈局

A:它們有不少不一樣點,最主要的區別就是flex-box是一種一維的佈局系統,而CSS網格是一種二維的佈局系統。讓咱們看看下圖:學習

grid image

圖一

Q:爲何不使用Bootstrap呢?flex

A:我認爲最好的回答是引用Jen Simmons的表述:

使用CSS Grid越多,使我更加確信,在其上添加抽象層沒有任何好處,CSS網格就是是嵌入瀏覽器的CSS佈局框架。

Q:CSS 網格爲用於生產環境準備好了嗎?

A:這取決於你的網站,你的網站是否要兼容IE,Opera mini,Blackberry browser,Baidu mobile等瀏覽器?若是回答是否認,你能夠直接用於生產環境。若是回答是確定,那麼你能夠在支持它的瀏覽器(不須要添加前綴的瀏覽器佔比:91.61%)使用它經過編寫@supportsCSS規則:

@supports (display: grid) {
  div {
    display: grid;
  }
}
複製代碼

基礎知識

基本上,一個網格佈局中能夠分解爲兩個元素:容器(grid container)和項目(grid-items)。

grid image

圖二

從圖二中咱們能夠看到,網格容器就是一個行和列的集合。一行就是兩根連續的水平線之間的空間,一列就是兩根連續的豎線之間的空間。一行被稱爲一個軌道(track),對於列也同樣。所以網格軌道就是兩根平行的網格線之間的空間。

每個軌道能夠有一個或者多個網格單元。cell就是最小的、最基本的網格單元,它是四根相交的網格線之間的空間。若是咱們把多個網格單元組合起來就造成了一個網格區域,值得一提的是網格區域必須是一個矩形區域,例如咱們不能產生一個T形狀的網格區域。

網格線從1開始到任何編號你能夠顯示或者隱式的定義,最後的網格線編號能夠被設爲-1,而在它以前的網格線編號爲-2,依此類推,這個在稍後的例子中會很方便。在圖二中列網格線的編號是從1增長6(或者是從-6到-1),行的網格線編號是從1增長到5(或者是從-5到-1)。

網格線的編號能夠被顯示的定義若是你在CSS樣式中明確設置,它也能夠被隱式地設置若是它是被瀏覽器動態地生成。

最後要補充地是,網格單元能夠經過空格和間距分開,這些間距被稱爲「槽」(gutters),可是咱們通常把它們當成間距。

2.CSS網格的基本屬性

好了,這樣咱們能夠開始實現一些網格佈局。首先咱們討論網格容器可使用的全部屬性,而後再介紹一下關於網格項(item)的一些屬性。

在本節中,讓咱們考慮以下模板:

<div class="grid-container">
    <div class="grid-item">grid item 1</div>
    <div class="grid-item">grid item 2</div>
    <div class="grid-item">grid item 3</div>
    <div class="grid-item">grid item 4</div>
    <div class="grid-item">grid item 5</div>
    <div class="grid-item">grid item 6</div>
    <div class="grid-item">grid item 7</div>
    <div class="grid-item">grid item 8</div>
    <div class="grid-item">grid item 9</div>
</div>
複製代碼

網格容器

Display

CSS網格是使用display屬性的grid值定義的 ,所以,使用上面的模板定義網格佈局,咱們應該這樣作:

.grid-containter {
  display: grid;
}
複製代碼

列 & 行

咱們能夠經過使用grid-template-rowsgrid-template-columns屬性定義網格的行和列:

.grid-container {
  grid-template-columns:  1fr 1fr 1fr 1fr;
  grid-template-rows:  1fr auto 2fr;
}
複製代碼

或者咱們可使用grid-template屬性首先定義grid-template-rows而後定義grid-template-columns(使用斜杆分隔):

.grid-container {
  grid-template:  1fr auto 2fr  / 1fr 1fr 1fr 1fr;
}
複製代碼

順便提一下,fr是一個分數單位,所以1fr就是可用空間的一個部分。

Repeat function

repeat函數表示軌道(track)列表的一個重複片斷,所以咱們能夠獲得和上面同樣的模板經過以下代碼:

.grid-container {
  grid-template:  1fr auto 2fr / repeat(4, 1fr);
}
複製代碼

閱讀文檔repeat 能夠了解怎麼使用auto-fitauto-fill動態地添加軌道(track)。

Minmax function

minmax函數定義了一個尺寸的範圍,該範圍大於或者等於最小值,小於或者等於最大值,咱們能夠將該函數和repeat一塊兒使用:

.grid-container {
  grid-columns:  repeat(3, minmax(100px, 1fr));
}
複製代碼

間距

咱們可使用row-gap給行與行之間設置間距,一樣也可使用column-gap給列與列設置間距:

.grid-container {
  row-gap: 5px;
  column-gap: 10px;
}
複製代碼

咱們也可使用gap屬性先定義行間距而後定義列間距:

.grid-container {
  gap: 5px 10px;
}
複製代碼

若是row-gapcolumn-gap值是同樣的,咱們只須要指定一個值。

網格項

指定一個網格項在網格佈局中的開始和結束位置,咱們基本上使用四個屬性,讓咱們先看下它們的定義。

屬性 定義
grid-row-start grid-row-start屬性經過提供一個行、一個span或者什麼都不提供來指定網格行在網格中的開始位置(自動)
grid-row-end grid-row-end屬性經過提供一個行、一個span或者什麼都不提供來指定網格行在網格中的結束位置(自動)
grid-column-start grid-column-start屬性經過提供一個行、一個span或者什麼都不提供來指定網格列在網格中的開始位置(自動)
grid-column-end grid-column-end屬性經過提供一個行、一個span或者什麼都不提供來指定網格列在網格中的結束位置(自動)

或者咱們也可使用這些屬性的簡寫形式:

屬性 定義
grid-row grid-row屬性是grid-row-startgrid-row-end的簡寫屬性,用於指定網格行中網格項的大小和位置
grid-column grid-column屬性是grid-column-startgrid-column-end的簡寫屬性,用來指定網格列中網格項的大小和位置

基本模板間距

考慮一下咱們在本節開始時使用的標記,假設咱們想要第三個網格項佔用四個單元格而不是一個(咱們但願它跨越兩個網格列和兩個網格行),效果就像圖三同樣,咱們該怎麼作了?

template spacing

圖三

咱們能夠像這樣實現:

// Grid container
.grid-container {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, 1fr);
}

// Grid item (third)
.grid-container .grid-item:nth-child(3) {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 3;
  // or
  grid-column: 1 / 3;
  grid-row: 1 / 3;
  // or
  grid-column: 1 / span 2;
  grid-row: 1 / span 2;
  // or
  grid-column: -5 / span 2; // because we have 4 columns
  grid-row: -4 / span 2; // because we have 3 rows
}
複製代碼

注意,第三個網格項其實就是圖三中的第一個,這與CSS網格能夠(第一次)擁有源碼順序獨立性有關。當咱們討論grid-auto-flow的時候,咱們還會講到這個知識點。

若是你想玩它,探索不一樣的解決方案,點擊這裏

3.高級模板

還有一些更高級的屬性能夠幫助您按照本身的須要調整模板。在這小節,咱們將學習這些屬性並知道如何在CSS中使用它們。

在這個小節,咱們考慮以下模板:

<div class="grid-container">
   <div class="grid-item header">Header</div>
   <div class="grid-item content">Content</div>
   <div class="grid-item navbar">Navbar</div>
   <div class="grid-item meta">Meta</div>
   <div class="grid-item footer">Footer</div>
 </div>
複製代碼

使用咱們前面學過的知識,咱們可使用以下的CSS樣式使得它看起來像一個基本的網站佈局:

.grid-container {
  grid-template: repeat(6, 1fr) / repeat(12, 1fr);// rows then columns
}
.grid-container .header {
  grid-column: 1 / -1;  
  grid-row: 1 / 2;
}
.grid-container .navbar {
  grid-column: 1 / 2;  
  grid-row: 2 / -1;
}
.grid-container .content {
  grid-column: 2 / -1;  
  grid-row: 2 / -2;
}
.grid-container .footer {
  grid-column: 2 / -1;  
  grid-row: -2 / -1;
}
.grid-container .meta {
  grid-column: -3 / -1;  
  grid-row: 2 / 4;
}
複製代碼

basic layout

圖四

如今假設咱們想要導航條(在右邊)寬一點,目前,它跨越了一列,可是咱們想要它跨越兩列。爲了實現這個效果,咱們須要改變.navbar的位置,同時也要改變.content.footer的位置,由於當前.navbar是從列1到列2,而.footer.content是從列2一直到最後。

若是每次都要修改元素的位置,那就太單調了。若是有一種辦法來告訴CSS網格自動爲咱們去作這件事,那就太好了。固然,不止有一種方法能夠實現,至少有兩種方法。

命名行

第一種解決方案就是命名特定的行,而後咱們能夠用它的別名而不是它的編號來引用它,讓咱們嘗試實現它。

.grid-container {
  grid-template-rows: repeat(6, 1fr);
  grid-template-columns: 1fr 1fr [content-start navbar-end] repeat(10, 1fr);
}
複製代碼

在上面的代碼中,咱們使用包含別名的簡單方括號爲第三行命名(單一的行能夠有多個別名)。而後咱們修改前面提到的元素的CSS代碼:

.grid-container .navbar {
  grid-column: 1 / navbar-end;  
  grid-row: 2 / -1;
}
.grid-container .content {
  grid-column: content-start / -1;  
  grid-row: 2 / -2;
}
.grid-container .footer {
  grid-column: content-start / -1;  
  grid-row: -2 / -1;
}
複製代碼

實現的效果像下面這樣:

extended navbar

圖五

嘗試對其它的行實現相同的效果(前面的:header-row-end / content-row-start)能夠點擊下面的代碼片斷

元素的模板區域

第二種解決方案是使用模板區域,grid-template-areas屬性用來指定命名的網格區域。這個屬性有個奇怪的CSS語法,但咱們像這樣使用它:

.grid-container {
  grid-template-areas:
    'h h h h h h h h h h h h'
    'n n c c c c c c c c c c'
    'n n c c c c c c c c c c'
    'n n c c c c c c c c c c'
    'n n c c c c c c c c c c'
    'n n f f f f f f f f f f';
}
.grid-container .navbar {
  grid-area: n;
}
.grid-container .content {
  grid-area: c;
}
.grid-container .footer {
  grid-area: f;
}
.grid-container .header {
  grid-area: h;
}
.grid-container .meta {
  grid-column: -3 / -1;  
  grid-row: 2 / 4;
}
複製代碼

咱們使用grid-template-areas定義網格容器區域,而後使用grid-area將網格項放置到須要的網格區域。值得注意的是,全部的區域必須是矩形。

注意,咱們沒有爲.meta元素使用grid-area,這是由於,目前沒有可使用這種方式來疊加元素的方法,至少我不知道。

你能夠繼續玩它,可用的代碼點擊這裏

4.隱式行和網格流

考慮以下代碼:

<div class="grid-container">
  <div class="grid-item">1</div>
  <div class="grid-item">2</div>
  <div class="grid-item">3</div>
  <div class="grid-item">4</div>
  <div class="grid-item">5</div>
  <div class="grid-item">6</div>
</div>
<style> .grid-container { grid-template-columns: repeat(3, minmax(100px, 1fr)); grid-template-rows: 80px; } .grid-container .grid-item:nth-child(2) { grid-row: span 2; } .grid-container .grid-item:nth-child(3) { grid-column: span 3; } </style>
複製代碼

咱們有一個三列的網格,咱們想讓第二個網格項跨越兩行,第三個跨越三列,結果以下圖:

bad grid

圖六

這看起來很糟糕,因此這裏發生了什麼?首先,第二個元素比一個元素稍微高了一點,由於咱們想要它高一倍,可是看起來根本不像是高了一倍的高度。一樣,從3到6的網格項也沒有第一個高。

隱式行

這與咱們顯示的設置第一行CSS樣式有關:grid-template-rows: 80px,而其它的行被隱式地建立了,所以,第二行幾乎是不可見的,由於它是空的,而其它行的大小取決於它們內容所須要的。

咱們能夠像下面代碼這樣使用grid-auto-rows屬性設置隱式建立的行高度來修復這個問題:

.grid-container {
  grid-template-columns: repeat(4, minmax(100px, 1fr));
  grid-template-rows: 80px;
  grid-auto-rows: 100px; 
} 
複製代碼

這樣看起來就像下圖同樣:

better grid, but still

圖七

這樣看起來好一點了,可是咱們仍然能夠作得更好。注意這些空白的空間,爲何咱們沒有使用它們放置網格4,5,6項,爲了作到這樣,咱們可使用grid-auto-flow

網格流

grid-auto-flow屬性控制自動放置算法的工做方式,準確地指定自動放置的網格項如何流入網格,它能夠有多個參數(你能夠點擊這裏瞭解更多),可是在這裏,咱們關心的只有一個:dense。這個值告訴瀏覽器將網格項放置在任何足夠大的空間:

.grid-container {
  grid-auto-flow: dense; // default is row
}
複製代碼

這樣咱們的網格看起來就很漂亮了:

good grid

圖八

結論

講到這裏,咱們須要處理大量的信息,可是有了這些知識,咱們涵蓋了大量的CSS網格屬性,所以咱們能夠愉快地在應用中使用CSS網格佈局。這篇文章是一系列文章中的第一篇,在下一篇中,咱們將使用網格實現三個實際的例子,所以跟上節奏。

我但願你一如既往地從文章中學到了有用的知識,快樂編程!

相關文章
相關標籤/搜索