網站的布局是一個網站設計的根本,CSS的Grid布局已經成為了未來網站布局的基本方式。
今天這篇文章我們通過圖文,一起看看如何自己實現Grid布局方式。
CSS
首先我們看看最基本的Grid布局是什么樣的,HTML頁面的代碼如下所示。
HTML代碼
然后設置其CSS屬性,這里主要展示容器的CSS屬性,給子元素添加的color屬性就不在這里展示了。
CSS屬性
在頁面上看到的效果如下,目前因為沒有對子div元素做任何設置,會自動將子div沿垂直方向排列。
頁面效果
為了讓外層的div(wrapper)為一個網格容器,需要設置其行數和列數,就像一個表格一樣。
此時就需要用到grid-template-columns和grid-template-rows兩個屬性值。
grid-template-columns
用于設置網格容器的列屬性,其實就相當于列的寬度。當我們需要幾列展示時,就設置幾個值,這個屬性可以接收具體數值比如100px,也可以接收百分比值,表示占據容器的寬度。
需要注意的是:當給容器設定了寬度時,grid-template-columns設定的百分比值是以容器的寬度值為基礎計算的。如果未設置寬度時,會一直向上追溯到設置了寬度的父容器,直到body元素。
比如我們設置了以下的CSS屬性。
CSS屬性
可以看出三列寬度加起來的百分比值為120%,而且wrapper容器并未設置寬度,會一直向上追溯到body元素,這樣三列的總寬度已經超過了body的寬度,因此會出現滾動條。
頁面效果
grid-template-rows
用于設置網格容器的行屬性,其實就相當于行的高度,其特性與grid-template-columns屬性類似。
下面簡單修改grid-template-columns和grid-template-rows兩個屬性的值。
CSS值
得到的效果圖如下所示。
效果圖
接下來我們看看別的情況,通過CSS屬性設置3*3的網格。
CSS屬性
在頁面上的呈現方式如下所示。
頁面呈現
從頁面上看我們看不出有什么問題,但是打開控制臺后可以發現,這個網格已經占據了3*3的空間。它后面的元素只能排列在所有的網格后面。
頁面實際情況
當我們需要得到特殊的排列方式,比如占滿整行,占滿整列,二三行合并等等。
這就需要用到grid-column和grid-row屬性,表示行網線和列網線的序號。通過設置start和end值,來進行網格的合并。
網線序號
我們重新給wrapper容器內部的div添加class類。
HTML代碼
然后添加以下的CSS代碼,給不同的網格特定的行號和列號。
CSS代碼
最終得到的效果圖如下所示。
頁面效果圖
今天這篇文章介紹了CSS中Grid布局的基礎知識,應該可以很快掌握,其他的復雜點的網格布局大家也可以自己去嘗試。
先看一個例子:
網格布局
簡單來說網格布局就是display: grid,將元素定義為一個網格容器,內部的子元素則變成網格元素。
display: grid; // 定義網格容器
grid-template-columns: 1fr 1fr 1fr; // 定義等寬的3列
grid-template-rows: 1fr 1fr; // 定義等高的兩行
grid-gap: .5em; // 給每個網格的單元格子間加上間隔
fr是一種新的單位,代表每一行或者列的分數單位(fraction unit)。
網格線(grid line):網格線構成了網格的框架。一條網格線可以水平或垂直,也可以位于一行或一列的任意一側。如果指定了grid-gap,它就位于網格線上。
網格軌道(grid track):一個網格軌道是兩條相鄰網格線之間的空間。網格有水平軌道和垂直軌道。
網格單元(grid cell):網格上的單個空間,水平和垂直的網格軌道交叉重疊的部分。
網格區域(grid area):網格的矩形區域,由一個到多個網格單元組成。
網格軌道定義好后,要將每個網格元素放到特定的位置上。瀏覽器給網格里的每個網格線都賦予了編號。
網格線編號
可以在grid-column和grid-row屬性中間用網格線的編號指定網格元素的位置。如果想要一個網格元素在垂直方向上跨越1號網格線到3號網格線,就需要給元素設置grid-column:1 / 3。
需要注意的是,網格的高度是隨著內容的高度自動計算的,比如上面a、c兩個網格分別占據了兩行,一共有5行,最終每行的高度是a、c內容高度的最大值除以所占的行數(2),如果我們設置a只占一行,那么每一行的高度就會放大接近2倍:
有時候記錄所有網格線的編號實在太麻煩了,為了能簡單點,可以給網格線命名:
grid-template-column: [start] 2fr [center] 1fr [end];
這條聲明定義了兩列的網格,三條垂直的網格線分別叫做start、center、end。之后在grid-colum中可以這樣寫:
grid-column: start / center;
可以將網格區域命名,然后將元素放到指定的網格中:
命名網格區域
需要注意的是,網格的命名一定要準確,并且不能少,不然網格就會錯位!
SS 網格布局(Grid Layout) 是CSS中最強大的布局系統。 這是一個二維系統,這意味著它可以同時處理列和行,不像 flexbox 那樣主要是一維系統。 你可以通過將CSS規則應用于父元素(成為網格容器)和該元素的子元素(網格元素),來使用網格布局。
引言
CSS網格布局(又名“網格”)是一個二維的基于網格的布局系統,其目的只在于完全改變我們設計基于網格的用戶界面的方式。 CSS一直用來布局網頁,但一直都不完美。 一開始我們使用table 做布局,然后轉向浮動、定位以及inline-block,但所有這些方法本質上都是 Hack 的方式,并且遺漏了很多重要的功能(例如垂直居中)。 Flexbox的出現在一定程度上解決了這個問題,但是它的目的是為了更簡單的一維布局,而不是復雜的二維布局(Flexbox和Grid實際上一起工作得很好)。 只要我們一直在制作網站,我們就一直在為解決布局問題不斷探索, 而Grid是第一個專門為解決布局問題而生的CSS模塊。
有兩個東西,啟發我寫這篇指南。 第一個是雷切爾·安德魯(Rachel Andrew)的書為CSS Grid布局準備。 這本書對網格布局做了徹底、清晰的介紹,也是是整篇文章的基礎,我強烈建議你購買并閱讀他的書。 我的另一個重要靈感是Chris Coyier的Flexbox完全指南,當需要查閱 flexbox 的一切資料時我就會找這篇文章。 這篇文章幫助了很多人學習 Flex 布局,也是 Google 上搜索“flexbox”關鍵字排名第一的文章。你會發現他的文章和我的很多相似之處,有最好的范例在那放著為什么咱不偷師學著寫呢?
本指南的目的是介紹網格概念,因為它們存在于最新版本的規范中。 因此我不會覆蓋過時的IE語法,而且隨著規范的成熟,我會盡最大努力保存更新本指南。
基礎知識以及瀏覽器支持情況
一開始你需要使用display:grid把容器元素定義為一個網格,使用grid-template-columns和grid-template-rows設置列和行大小,然后使用grid-column 和 grid-row把它的子元素放入網格。 與flexbox類似,網格子元素的原始順序不重要。 你的可以在 CSS 里以任意順序放置它們,這使得使用媒體查詢重新排列網格變得非常容易。 想象一下,我們需要定義整個頁面的布局,然后為了適應不同的屏幕寬度完全重新排列,我們只需要幾行CSS就能實現這個需求。 網格是有史以來最強大的CSS模塊之一。
截至2017年3月,許多瀏覽器都提供了原生的、不加前綴的對CSS Grid的支持,比如 Chrome(包括Android),Firefox,Safari(包括iOS)和Opera。 另一方面,Internet Explorer 10和11支持它,但需要使用過時的語法。 Edge瀏覽器已經宣布將支持標準的Grid語法,但暫未支持。
瀏覽器支持的詳細數據可在Caniuse查看。其中里面的數字表示該版本以上的瀏覽器支持Grid。
桌面瀏覽器
移動端 / 平板
除了微軟之外,瀏覽器制造商在 Grid 規范完全落地以前似乎并沒有放手讓 Gird 野生也長的打算。 這是一件好事,這意味著我們不需要再去學習各種瀏覽器兼容版本的舊語法。
在生產環境中使用Grid只是時間問題,但現在是我們該學習的時候了。
重要術語
在深入了解網格的概念之前,理解術語是很重要的。 由于這里所涉及的術語在概念上都是相似的,如果不先記住它們在網格規范中定義的含義,則很容易將它們彼此混淆。 但是不用太擔心,這些術語并不多。
Grid Container
設置了 display: gird 的元素。 這是所有 grid item 的直接父項。 在下面的例子中,.container 就是是 grid container。
<div class="container"> <div class="item item-1"></div> <div class="item item-2"></div> <div class="item item-3"></div> </div>
Grid Item
Grid 容器的孩子(直接子元素)。下面的 .item 元素就是 grid item,但 .sub-item不是。
<div class="container"> <div class="item"></div> <div class="item"> <p class="sub-item"></p> </div> <div class="item"></div> </div>
Grid Line
這個分界線組成網格結構。 它們既可以是垂直的(“column grid lines”),也可以是水平的(“row grid lines”),并位于行或列的任一側。 下面例中的黃線就是一個列網格線。
Grid Track
兩個相鄰網格線之間的空間。 你可以把它們想象成網格的列或行。 下面是第二行和第三行網格線之間的網格軌道。
Grid Cell
兩個相鄰的行和兩個相鄰的列網格線之間的空間。它是網格的一個“單元”。 下面是行網格線1和2之間以及列網格線2和3的網格單元。
Grid Area
四個網格線包圍的總空間。 網格區域可以由任意數量的網格單元組成。 下面是行網格線1和3以及列網格線1和3之間的網格區域。
Grid 屬性列表
Grid Container 的全部屬性
Grid Items 的全部屬性
父容器(Grid Container)的屬性
display
將元素定義為 grid contaienr,并為其內容建立新的網格格式化上下文(grid formatting context)。
值:
.container { display: grid | inline-grid | subgrid; }
注意:column, float, clear, 以及 vertical-align 對一個 grid container 沒有影響
grid-template-columns / grid-template-rows
使用以空格分隔的多個值來定義網格的列和行。這些值表示軌道大小(track size),它們之間的空格代表表格線(grid line)。
.container { grid-template-columns: <track-size> ... | <line-name> <track-size> ...; grid-template-rows: <track-size> ... | <line-name> <track-size> ...; }
例子:
(如果未顯示的給網格線命名),軌道值之間僅僅有空格時,網格線會被自動分配數字名稱:
.container { grid-template-columns: 40px 50px auto 50px 40px; grid-template-rows: 25% 100px auto; }
但你可以給網格線指定確切的命名。 注意中括號里的網格線命名語法:
.container { grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end]; grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line]; }
需要注意的是,一個網格線可以有不止一個名字。例如,這里第2條網格線有兩個名字:row1-end 和 row2-start:
.container { grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end]; }
如果你的定義中包含重復的部分,則可以使用repeat() 符號來簡化寫法:
.container { grid-template-columns: repeat(3, 20px [col-start]) 5%; }
上面的寫法和下面等價:
.container { grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start] 5%; }
“fr”單位允許您將軌道大小設置為網格容器自由空間的一部分。 例如,下面的代碼會將每個 grid item 為 grid container 寬度的三分之一:
.container { grid-template-columns: 1fr 1fr 1fr; }
自由空間是在排除所有不可伸縮的 grid item 之后計算得到的。 在下面的示例中,fr單位可用的自由空間總量不包括50px:
.container { grid-template-columns: 1fr 50px 1fr 1fr; }
grid-template-areas
通過引用 grid-area屬性指定的網格區域的名稱來定義網格模板。 重復網格區域的名稱導致內容擴展到這些單元格。 點號表示一個空單元格。 語法本身提供了網格結構的可視化。
值:
舉例:
.item-a { grid-area: header; } .item-b { grid-area: main; } .item-c { grid-area: sidebar; } .item-d { grid-area: footer; } .container { grid-template-columns: 50px 50px 50px 50px; grid-template-rows: auto; grid-template-areas: "header header header header" "main main . sidebar" "footer footer footer footer"; }
這將創建一個四列寬三行高的網格。 整個第一行將由 header 區域組成。 中間一行將由兩個 main 區域、一個空單元格和一個 sidebar 區域組成。 最后一行是footer區域組成。
你的聲明中的每一行都需要有相同數量的單元格。
您可以使用任意數量的相鄰的.來聲明單個空單元格。 只要這些點號之間沒有空格,他們就代表了一個單一的單元格。
需要注意的是你不是在用這個語法命名網格線,而是在命名區域。 當你使用這種語法時,區域兩端的網格線實際上是自動命名的。 比如,如果網格區域的名稱是foo,那么區域的起始的行網格線和列網格線名稱是 foo-start,并且區域終點的行網格線和列網格線名稱是 foo-end。 這意味著某些網格線可能有多個名稱,比如上面的例子中最左邊的一條網格線有三個名字:header-start,main-start 和 footer-start。
grid-template
在單個聲明中定義 grid-template-rows、grid-template-columns、grid-template-areas 的簡寫。
值:
.container { grid-template: none | subgrid | <grid-template-rows> / <grid-template-columns>; }
它也可以使用一個更復雜但相當方便的語法來指定這三個值。 一個例子:
.container { grid-template: [row1-start] "header header header" 25px [row1-end] [row2-start] "footer footer footer" 25px [row2-end] / auto 50px auto; }
以上等價于:
.container { grid-template-rows: [row1-start] 25px [row1-end row2-start] 25px [row2-end]; grid-template-columns: auto 50px auto; grid-template-areas: "header header header" "footer footer footer"; }
由于 grid-template 不會重置隱式網格屬性(grid-auto-columns,grid-auto-rows和grid-auto-flow),而這可能是大多數情況下你想要做的。因此建議使用grid屬性來代替grid-template。
grid-column-gap / grid-row-gap
指定網格線的大小,你可以把它想象為設置列/行之間的間距的寬度。
值:
.container { grid-column-gap: <line-size>; grid-row-gap: <line-size>; }
舉例:
.container { grid-template-columns: 100px 50px 100px; grid-template-rows: 80px auto 80px; grid-column-gap: 10px; grid-row-gap: 15px; }
只能在列/行之間創建縫隙,而不是在外部邊緣創建。
grid-gap
grid-row-gap 和 grid-column-gap 的縮寫
.container { grid-gap: <grid-row-gap> <grid-column-gap>; }
Example:
.container { grid-template-columns: 100px 50px 100px; grid-template-rows: 80px auto 80px; grid-gap: 10px 15px; }
如果沒有指定 grid-row-gap,則會被設置為與 grid-column-gap 相同的值。
justify-items
沿著行軸對齊網格內的內容(與之對應的是 align-items, 即沿著列軸對齊),該值適用于容器內的所有的 grid items。
值:
.container { justify-items: start | end | center | stretch; }
舉例:
.container { justify-items: start; }
.container{ justify-items: end; }
.container { justify-items: center; }
.container { justify-items: stretch; }
也可以通過給單個 grid item 設置justify-self屬性來達到上述效果。
align-items
沿著列軸對齊grid item 里的內容(與之對應的是使用 justify-items 設置沿著行軸對齊),該值適用于容器內的所有 grid items。
值:
.container { align-items: start | end | center | stretch; }
舉例:
.container { align-items: start; }
.container { align-items: end; }
.container { align-items: center; }
.container { align-items: stretch; }
也可以通過給單個 grid item 設置align-self屬性來達到上述效果。
justify-content
有時,網格的總大小可能小于其網格容器的大小。如果你的所有 grid items 都使用像px這樣的非彈性單位來設置大小,則可能發生這種情況。此時,你可以設置網格容器內的網格的對齊方式。 此屬性沿著行軸對齊網格(與之對應的是 align-content, 沿著列軸對齊)。
值:
.container { justify-content: start | end | center | stretch | space-around | space-between | space-evenly; }
舉例:
.container { justify-content: start; }
.container { justify-content: end; }
.container { justify-content: center; }
.container { justify-content: stretch; }
.container { justify-content: space-around; }
.container { justify-content: space-between; }
.container { justify-content: space-evenly; }
align-content
有時,網格的總大小可能小于其網格容器的大小。如果你的所有 grid items 都使用像px這樣的非彈性單位來設置大小,則可能發生這種情況。此時,你可以設置網格容器內的網格的對齊方式。 此屬性沿著列軸對齊網格(與之對應的是 justify-content, 即沿著行軸對齊)。
值:
.container { align-content: start | end | center | stretch | space-around | space-between | space-evenly; }
舉例:
.container { align-content: start; }
.container { align-content: end; }
.container { align-content: center; }
.container { align-content: stretch; }
.container { align-content: space-around; }
.container { align-content: space-between; }
.container { align-content: space-evenly; }
grid-auto-columns / grid-auto-rows
指定自動生成的網格軌道(又名隱式網格軌道)的大小。 隱式網格軌道在你顯式的定位超出指定網格范圍的行或列(使用 grid-template-rows/grid-template-columns)時被創建。
值:
.container { grid-auto-columns: <track-size> ...; grid-auto-rows: <track-size> ...; }
為了說明如何創建隱式網格軌道,思考如下代碼:
.container { grid-template-columns: 60px 60px; grid-template-rows: 90px 90px }
這里創建了一個 2x2的網格。
但是,現在想象一下,使用 grid-column 和 grid-row 來定位你的網格項目,如下所示:
.item-a { grid-column: 1 / 2; grid-row: 2 / 3; } .item-b { grid-column: 5 / 6; grid-row: 2 / 3; }
這里我們指定 .item-b開始于列網格線 5 并結束于在列網格線 6,但我們并未定義列網格線 5 或 6。因為我們引用不存在的網格線,寬度為0的隱式軌道的就會被創建用與填補間隙。我們可以使用 grid-auto-columns 和 grid-auto-rows屬性來指定這些隱式軌道的寬度:
.container { grid-auto-columns: 60px; }
grid-auto-flow
如果你存在沒有顯示指明放置在網格上的 grid item,則自動放置算法會自動放置這些項目。 而該屬性則用于控制自動布局算法的工作方式。
值:
.container { grid-auto-flow: row | column | row dense | column dense }
需要注意的是,dense 可能導致您的 grid item 亂序。
舉例, 考慮如下 HTML:
<section class="container"> <div class="item-a">item-a</div> <div class="item-b">item-b</div> <div class="item-c">item-c</div> <div class="item-d">item-d</div> <div class="item-e">item-e</div> </section>
你定義一個有5列和2行的網格,并將 grid-auto-flow 設置為 row(這也是默認值):
.container { display: grid; grid-template-columns: 60px 60px 60px 60px 60px; grid-template-rows: 30px 30px; grid-auto-flow: row; }
當把 grid item 放在網格上時,你只把其中兩個設置了固定的位置:
.item-a { grid-column: 1; grid-row: 1 / 3; } .item-e { grid-column: 5; grid-row: 1 / 3; }
因為我們將 grid-auto-flow 設置為row,所以我們的grid就像這樣。 注意觀察我們沒有做設置的三個項目(item-b,item-c和item-d)是如何在剩余的行水平擺放位置的:
如果我們將 grid-auto-flow 設置為 column,則 item-b,item-c 和 item-d 以列的順序上下擺放:
.container { display: grid; grid-template-columns: 60px 60px 60px 60px 60px; grid-template-rows: 30px 30px; grid-auto-flow: column; }
grid
在單個屬性中設置所有以下屬性的簡寫:grid-template-rows,grid-template-columns,grid-template-areas,grid-auto-rows,grid-auto-columns和grid-auto-flow。 它同時也將 sets grid-column-gap 和 grid-row-gap 設置為它們的初始值,即使它們不能被此屬性顯示設置。
值:
.container { grid: none | <grid-template-rows> / <grid-template-columns> | <grid-auto-flow> [<grid-auto-rows> [/ <grid-auto-columns>]]; }
舉例:
以下代碼寫法等價
.container { grid: 200px auto / 1fr auto 1fr; } .container { grid-template-rows: 200px auto; grid-template-columns: 1fr auto 1fr; grid-template-areas: none; }
以下代碼寫法等價
.container { grid: column 1fr / auto; } .container { grid-auto-flow: column; grid-auto-rows: 1fr; grid-auto-columns: auto; }
它也可用使用一個更復雜但相當方便的語法來一次設置所有內容。 你可以指定 grid-template-areas、grid-template-rows 以及 grid-template-columns,并將所有其他子屬性設置為其初始值。 你現在所做的是在其網格區域內,指定網格線名稱和內聯軌道大小。 可以看下面的例子:
.container { grid: [row1-start] "header header header" 1fr [row1-end] [row2-start] "footer footer footer" 25px [row2-end] / auto 50px auto; }
上述代碼等價于
.container { grid-template-areas: "header header header" "footer footer footer"; grid-template-rows: [row1-start] 1fr [row1-end row2-start] 25px [row2-end]; grid-template-columns: auto 50px auto; }
孩子(Grid Items)的屬性
grid-column-start / grid-column-end / grid-row-start /grid-row-end
使用特定的網格線確定 grid item 在網格內的位置。grid-column-start/grid-row-start 屬性表示grid item的網格線的起始位置,grid-column-end/grid-row-end屬性表示網格項的網格線的終止位置。
值:
.item { grid-column-start: <number> | <name> | span <number> | span <name> | auto grid-column-end: <number> | <name> | span <number> | span <name> | auto grid-row-start: <number> | <name> | span <number> | span <name> | auto grid-row-end: <number> | <name> | span <number> | span <name> | auto }
舉例:
.item-a { grid-column-start: 2; grid-column-end: five; grid-row-start: row1-start grid-row-end: 3 }
.item-b { grid-column-start: 1; grid-column-end: span col4-start; grid-row-start: 2 grid-row-end: span 2 }
如果沒有聲明 grid-column-end / grid-row-end,默認情況下,該網格項將跨越1個軌道。
網格項可以相互重疊。 您可以使用z-index來控制它們的堆疊順序。
grid-column / grid-row
grid-column-start + grid-column-end, 和 grid-row-start + grid-row-end 的簡寫形式。
值:
.item { grid-column: <start-line> / <end-line> | <start-line> / span <value>; grid-row: <start-line> / <end-line> | <start-line> / span <value>; }
舉例:
.item-c { grid-column: 3 / span 2; grid-row: third-line / 4; }
如果沒有指定結束行值,則該網格項默認跨越1個軌道。
grid-area
給 grid item 進行命名以便于使用 grid-template-areas 屬性創建模板時來進行引用。另外也可以做為 grid-row-start + grid-column-start + grid-row-end + grid-column-end 的簡寫形式。
值:
.item { grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>; }
舉例:
給一個網格項命名
.item-d { grid-area: header }
作為 grid-row-start + grid-column-start + grid-row-end + grid-column-end 的簡寫:
.item-d { grid-area: 1 / col4-start / last-line / 6 }
justify-self
沿著行軸對齊grid item 里的內容(與之對應的是 align-self, 即沿列軸對齊)。 此屬性對單個網格項內的內容生效。
值:
舉例:
.item-a { justify-self: start; }
.item-a { justify-self: end; }
.item-a { justify-self: center; }
.item-a { justify-self: stretch; }
要為網格中的所有grid items 設置對齊方式,也可以通過 justify-items 屬性在網格容器上設置此行為。
align-self
沿著列軸對齊grid item 里的內容(與之對應的是 justify-self, 即沿行軸對齊)。 此屬性對單個網格項內的內容生效。
值:
.item { align-self: start | end | center | stretch; }
舉例:
.item-a { align-self: start; }
.item-a { align-self: end; }
.item-a { align-self: center; }
.item-a { align-self: stretch; }
要為網格中的所有grid items 統一設置對齊方式,也可以通過 align-items 屬性在網格容器上設置此行為。
譯者:若愚老師
原文鏈接:https://zhuanlan.zhihu.com/p/33030746
*請認真填寫需求信息,我們會在24小時內與您取得聯系。