網格
CSS網格是一個用於web的二維布局系統。利用網格,你可以把內容按照行與列的格式進行排版。另外,網格還能非常輕松地實現一些復雜的布局。關於使用網格進行頁面排版,這篇文章包含了你需要的一切知識。
什么是網格布局?
網格是由一系列水平及垂直的線構成的一種布局模式。根據網格,我們能夠將設計元素進行排列,幫助我們設計一系列具有固定位置以及寬度的元素的頁面,使我們的網站頁面更加統一。
一個網格通常具有許多的列(column)與行(row),以及行與行、列與列之間的間隙,這個間隙一般被稱為溝槽(gutter)。

定義一個網格
一如既往,你可以下載教程文件(你可以在線看到效果)。例子中有一個容器,容器中有一些子項。默認情況下,子項按照正常布局流自頂而下排布。在這篇文章中,我們會從這開始,對這些文件做一些改變,來了解網格是如何工作的。
首先,將容器的display屬性設置為grid來定義一個網絡。與彈性盒子一樣,將父容器改為網格布局后,他的直接子項會變為網格項。把下面的css規則加到你的文件中。
.container { display: grid; }
與彈性盒子不同的是,在定義網格后,網頁並不會馬上發生變化。因為display: grid的聲明只創建了一個只有一列的網格,所以你的子項還是會像正常布局流那樣從上而下一個接一個的排布。
為了讓我們的容器看起來更像一個網格,我們要給剛定義的網格加一些列。那就讓我們加三個寬度為200px的列。當然,這里可以用任何長度單位,包括百分比。
.container { display: grid; grid-template-columns: 200px 200px 200px; }
在規則里加入你的第二個聲明。刷新頁面后,你會看到子項們排進了新定義的網格中。

使用fr單位的靈活網格
除了長度和百分比,我們也可以用fr這個單位來靈活地定義網格的行與列的大小。這個單位表示了可用空間的一個比例,可能有點抽像,看看下面的例子吧。
使用下面的規則來創建3個1fr的列:
.container { display: grid; grid-template-columns: 1fr 1fr 1fr; }
將窗口調窄(由於示例中設定了max-width,可能需要很窄),你應該能看到每一列的寬度可以會隨着可用空間變小而變小。fr 單位按比例划分了可用空間,如果沒有理解,可以試着改一下數值,看看會發生什么,比如下面的代碼:
.container { display: grid; grid-template-columns: 2fr 1fr 1fr; }
這個定義里,第一列被分配了2fr可用空間,余下的兩列各被分配了1fr的可用空間,這會使得第一列的寬度是第二第三列的兩倍。另外,fr可以與一般的長度單位混合使用,比如grid-template-columns: 300px 2fr 1fr,那么第一列寬度是300px,剩下的兩列會根據除去300px后的可用空間按比例分配。

注意:fr單位分配的是可用空間而非所有空間,所以如果某一格包含的內容變多了,那么整個可用空間就會減少,可用空間是不包括那些已經確定被占用的空間的。
網格間隙
使用 grid-column-gap (en-US) 屬性來定義列間隙;使用 grid-row-gap (en-US) 來定義行間隙;使用 grid-gap (en-US) 可以同時設定兩者。
.container { display: grid; grid-template-columns: 2fr 1fr 1fr; grid-gap: 20px; }
間隙距離可以用任何長度單位包括百分比來表示,但不能使用fr單位。

注意:*gap屬性曾經有一個grid-前綴,不過后來的標准進行了修改,目的是讓他們能夠在不同的布局方法中都能起作用。盡管現在這個前綴不會影響語義,但為了代碼的健壯性,你可以把兩個屬性都寫上。
.container { display: grid; grid-template-columns: 2fr 1fr 1fr; grid-gap: 20px; gap: 20px; }
重復構建行/列
你可以使用repeat來重復構建具有某些寬度配置的某些列。舉個例子,如果要創建多個等寬軌道,可以用下面的方法。
.container { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 20px; }
和之前一樣,你仍然得到了3個1fr的列。第一個傳入repeat函數的值(3)表明了后續列寬的配置要重復多少次,而第二個值(1fr)表示需要重復的構建配置,這個配置可以具有多個長度設定。例如repeat(2, 2fr 1fr),如果你仍然不明白,可以實際測試一下效果,這相當於填入了2fr 1fr 2fr 1fr。
顯式網格與隱式網格
到目前為止,我們定義過了列,但還沒有管過行。但在這之前,我們要來理解一下顯式網格和隱式網格。顯式網格是我們用grid-template-columns 或 grid-template-rows 屬性創建的。而隱式網格則是當有內容被放到網格外時才會生成的。顯式網格與隱式網格的關系與彈性盒子的main和cross軸的關系有些類似。
隱式網格中生成的行/列大小是參數默認是auto,大小會根據放入的內容自動調整。當然,你也可以使用grid-auto-rows和grid-auto-columns屬性手動設定隱式網格的大小。下面的例子將grid-auto-rows設為了100px,然后你可以看到那些隱式網格中的行(因為這個例子里沒有設定grid-template-rows,因此,所有行都位於隱式網格內)現在都是100像素高了。
譯者注:簡單來說,隱式網格就是為了放顯式網格放不下的元素,瀏覽器根據已經定義的顯式網格自動生成的網格部分。
.container { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 100px; grid-gap: 20px; }
方便的minmax() 函數
100像素高的行/列有時可能會不夠用,因為時常會有比100像素高的內容加進去。所以,我們希望可以將其設定為至少100像素,而且可以跟隨內容來自動拓展尺寸保證能容納所有內容。顯而易見,你很難知道網頁上某個元素的尺寸在不同情況下會變成多少,一些額外的內容或者更大的字號就會導致許多能做到像素級精准的設計出現問題。所以,我們有了minmax函數。
minmax 函數為一個行/列的尺寸設置了取值范圍。比如設定為 minmax(100px, auto),那么尺寸就至少為100像素,並且如果內容尺寸大於100像素則會根據內容自動調整。在這里試一下把 grid-auto-rows 屬性設置為minmax函數。
.container { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: minmax(100px, auto); grid-gap: 20px; }
如果所有網格內的內容均小於100像素,那么看起來不會有變化,但如果在某一項中放入很長的內容或者圖片,你可以看到這個格子所在的哪一行的高度變成能剛好容納內容的高度了。注意我們修改的是grid-auto-rows ,因此只會作用於隱式網格。當然,這一項屬性也可以應用於顯示網格,更多內容可以參考minmax頁面。
自動使用多列填充
現在來試試把學到的關於網格的一切,包括repeat與minmax函數,組合起來,來實現一個非常有用的功能。某些情況下,我們需要讓網格自動創建很多列來填滿整個容器。通過設置grid-template-columns屬性,我們可以實現這個效果,不過這一次我們會用到repeat函數中的一個關鍵字auto-fill來替代確定的重復次數。而函數的第二個參數,我們使用minmax函數來設定一個行/列的最小值,以及最大值1fr。
在你的文件中試試看,你也許可以用到以下的代碼。
.container { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-auto-rows: minmax(100px, auto); grid-gap: 20px; }

你應該能看到形成了一個包含了許多至少200像素寬的列的網格,將容器填滿。隨着容器寬度的改變,網格會自動根據容器寬度進行調整,每一列的寬度總是大於200像素,並且容器總會被列填滿。(This works because grid is creating as many 200 pixel columns as will fit into the container, then sharing whatever space is leftover between all of the columns — the maximum is 1fr which, as we already know, distributes space evenly between tracks.)
基於線的元素放置
在定義完了網格之后,我們要把元素放入網格中。我們的網格有許多分隔線,第一條線的起始點與文檔書寫模式相關。在英文中,第一條列分隔線(即網格邊緣線)在網格的最左邊而第一條行分隔線在網格的最上面。而對於阿拉伯語,第一條列分隔線在網格的最右邊,因為阿拉伯文是從右往左書寫的。
我們根據這些分隔線來放置元素,通過以下屬性來指定從那條線開始到哪條線結束。
這些屬性的值均為分隔線序號,你也可以用以下縮寫形式來同時指定開始與結束的線。
注意開始與結束的線的序號要使用/符號分開。
下載這個文件(或者查看在線預覽)。文件中已經定義了一個網格以及一篇簡單的文章位於網格之外。你可以看到元素已經被自動放置到了我們創建的網格中。
接下來,嘗試用定義網格線的方法將所有元素放置到網格中。將以下規則加入到你的css的末尾:
header { grid-column: 1 / 3; grid-row: 1; } article { grid-column: 2; grid-row: 2; } aside { grid-column: 1; grid-row: 2; } footer { grid-column: 1 / 3; grid-row: 3; }


注意:你也可以用-1來定位到最后一條列分隔線或是行分隔線,並且可以用負數來指定倒數的某一條分隔線。但是這只能用於顯式網格,對於隱式網格-1不一定能定位到最后一條分隔線。
使用grid-template-areas屬性放置元素
另一種往網格放元素的方式是用grid-template-areas屬性,並且你要命名一些元素並在屬性中使用這些名字作為一個區域。
將之前基於線的元素放置代碼刪除(或者重新下載一份新的文件),然后加入以下CSS規則:
.container { display: grid; grid-template-areas: "header header" "sidebar content" "footer footer"; grid-template-columns: 1fr 3fr; grid-gap: 20px; } header { grid-area: header; } article { grid-area: content; } aside { grid-area: sidebar; } footer { grid-area: footer; }
刷新頁面,然后你應該能看到的元素會被放到與之前相同的地方,整個過程不需要我們指定任何分隔線序號。


grid-template-areas屬性的使用規則如下:
- 你需要填滿網格的每個格子
- 對於某個橫跨多個格子的元素,重復寫上那個元素
grid-area屬性定義的區域名字 - 所有名字只能出現在一個連續的區域,不能在不同的位置出現
- 一個連續的區域必須是一個矩形
- 使用
.符號,讓一個格子留空
你可以在文件中盡情發揮你的想象來測試各種網格排版,比如把頁腳放在內容之下,或者把側邊欄一直延伸到最底。這種直觀的元素放置方式很棒,你在CSS中看到的就是實際會出現的排版效果。
一個用CSS網格實現的網格排版框架
網格排版框架一般由12到16列的網格構成,你可以用CSS網格系統直接實現而不需要任何第三方的工具,畢竟這是標准定義好了的。
下載這個初始文件,文件中包含了一個定義了12列網格的容器。文件中的一些內容我們曾在前兩個示例中使用過,我們暫時可以先用基於線的元素放置模式來將我們的內容放到這個12列的網格中。
header { grid-column: 1 / 13; grid-row: 1; } article { grid-column: 4 / 13; grid-row: 2; } aside { grid-column: 1 / 4; grid-row: 2; } footer { grid-column: 1 / 13; grid-row: 3; }


你可以使用Firefox Grid Inspector去查看頁面中的網格線,你應該能看到這12列的網格是如何工作的。


