網格(grid)
網格
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,2fr1fr)
,如果你仍然不明白,可以實際測試一下效果,這相當於填入了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列的網格是如何工作的。