grid佈局是一種新的佈局方案。傳統佈局使用浮動和定位,而grid佈局可以像表格一樣將頁面容器分割成一塊一塊的區域,定義子元素的排布和位置。可以說是flex佈局的升級版。
借用大神旭哥的話:
Grid佈局就像是“分田種地”。故事是這樣的,張老闆是個程式設計師,省吃儉用攢了點小錢,然後老家因為城鎮化建設,農村都沒什麼人,土地都荒廢在那裡,於是就承包了一塊地,打算養養魚,種種果樹。承包的地方很挺大,如何劃分土地就成了問題,於是張老闆打算藉助Grid佈局來劃分。
對於身為碼農的我們來說,種地就對了!
相容性
Grid佈局是微軟在2010年提出來的一種新的佈局方式,到2016年的時候提交了該佈局的草案。經過近幾年發展,相容性越來越好。
引用自 Can I Use 。相容火狐52+、谷歌57+等現代瀏覽器,IE10和11需要新增-ms-來實現相容。
名詞概念
Grid Container、Grid Items(網格容器、網格項)
元素應用 display: grid;
即成為網格容器,它是所有網格項的父元素。
很好理解,下面這個例子,class為container的div設定了 display: grid;
,container就是網格容器,裡面的item都是網格項。
<style>
.container{ display: grid; }
</style>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>
Grid Lines(網格線)
所謂的網格都是由橫向和豎向的若干線交錯產生的,這些線就是網格線。
熟知數學的我們知道,正常情況下,n行有n + 1根水平網格線,m列有m + 1根垂直網格線,比如三行就有四根水平網格線。
網格線是定義容器的時候產生的,和網格項沒有直接的關係,網格項是直接存在於html中的,但是網格線正常看不到它。說白了網格線是虛擬的。
Grid Track(網格軌道)
兩個相鄰的網格線之間為網格軌道。
網格軌道的特點是能接觸到網格容器的邊緣。
Grid Cell(網格單元)
兩個相鄰的列網格線和兩個相鄰的行網格線之間的空間為網格單元,類似於excel中的單元格。
Grid Areas(網格區域)
四條網格線包圍的地方稱為網格區域,類似於excel中的合併單元格。
關鍵字
fr(剩餘空間分配數)
fr單位被用於在一系列長度值中分配剩餘空間,如果多個已指定了多個部分,則剩下的空間根據各自的數字按比例分配。
gr(網格數)
目前未被w3c採納,可以作為了解。
屬性
介紹完概念,進入正題。
gird佈局的屬性可以分為兩類:容器屬性和專案屬性。
容器屬性分為這幾類:
- display:佈局方式
- grid-template:定義網格線的名稱和網格軌道的尺寸大小
- gap:定義網格項之間的間隙
- items:定義網格單元內容的位置
- content:定義整個內容區域在容器裡面的位置
- grid-auto:定義多餘網格的大小
- grid-auto-flow:定義網格項的放置順序
專案屬性分為這幾類:
- column / row:指定專案位於哪(些)條網格線
- area:指定專案放在哪一個區域
- self:指定網格單元內容的位置
下面來看具體的使用
容器屬性
1. display
有三種取值:grid | inline-grid | subgrid
gird:生成塊級網格
inline-grid: 生成行內網格
subgrid: 網格容器本身就是網格項(巢狀網格容器),此屬性用來繼承其父網格容器的行、列大小。(目前所有瀏覽器都不相容)
注意,設為網格佈局以後,容器子元素(專案)的float、display: inline-block、display: table-cell、vertical-align和column-*等設定都將失效。但是position是不會失效的。
2.1 grid-template-columns和grid-template-rows
grid-template-columns用來定義每一列的寬度,grid-template-rows用來定義每一行的高度。
.container{
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
}
上面這個例子,就是一個三行五列的網格佈局。
- grid-template-columns的取值可以是絕對長度(px、em)、百分比、auto、fr、函式。
- auto表示由瀏覽器自己決定長度。
函式&關鍵字:
$minmax(min, max):$
- 用來定義一個範圍,最小值為min,最大值為max。
- max可以設定為fr,min不可以。
- 如果max值小於min值,則該值會被視為min值。
.container{
grid-template-columns: 40px 50px minmax(50px, 2fr) 1fr 40px;
grid-template-rows: 25% 100px auto;
}
$repeat(repeat, values):$
- 表示軌道列表的重複片段,允許以更緊湊的形式寫入大量顯示重複模式的列或行。
- 第一個值repeat可以是固定的數字(n),表示重複n次,也可以是
auto-fit
或auto-fill
,表示自動填充,容納不下的放到下一行。
例如:
/* css */
.container{
width: 800px;
height: 300px;
display: grid;
grid-template-columns: repeat(auto-fit, 200px);
grid-template-rows: auto auto;
gap: 5px;
}
<!--html-->
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
</div>
這裡有兩點要注意:
- 佈局設定的是兩行,最終由於單個軌道容納不下,最終變成4行。多出的這兩行可以用
grid-auto-rows
來進行設定,這個屬性後面會講到。 auto-fit
和auto-fill
通常是沒有區別的,只有在容器寬度大於子元素的最小寬度總和時才有顯示區別。
我們來把上面的例子稍微改動一下,
.container{
grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
}
我們再看一下auto-fit
。
.container{
grid-template-columns: repeat(auto-fit, minmax(50px, 1fr));
}
可以發現,使用auto-fill
的網格寬度為52.5px,auto-fit
的網格寬度為75.5px
這個值我們可以計算一下
假設一行有n個單元格,兩個單元格之間的間隙是5
所以 $50n + 5(n - 1) = 800$,n ≈ 14.6,向下取整得到14
有了列數,假設單元格寬度為 $x$ 帶入上面這個式子:$14x + 5*13 = 800$,得到單元格寬度為52.5px
。
由此可知
auto-fit
和auto-fill
都會以最小的寬度建立單元格,建立完成以後,如果有多餘的單元格,auto-fit
會把這些多餘的單元格均分給每一網格項,再重新建立單元格,而auto-fill
不會。- 需要注意的是:只有在容器寬度大於子元素的最小寬度總和時才會這樣,除此之外兩者的顯示是一樣的。
網格線名稱:
grid-template-columns屬性裡面,還可以使用方括號,指定每一根網格線的名字,方便以後的引用。
名字可以寫多個,用空格隔開。
.container{
grid-template-columns: [c1 r1] 40px [c2] 50px [c3] auto [c4] 50px [c5] 40px;
grid-template-rows: 25% 100px auto;
}
grid-template-rows的用法與grid-template-columns完全一樣。
2.2 grid-template-areas
areas是區域的意思,grid-template-areas用來給各個網格單元命名,就像給網格線命名一個道理。寫法上類似於矩陣。
.container{
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
grid-template-areas:
'a a a b b'
'c c d . e'
'c c d . e';
}
上面這個例子將網格分為a、b、c、d、e五個區域。如果某些區域不需要利用,則使用"點"(.)表示。
需要注意:
- 寫法上分號的位置,最後單元格的末尾才加分號。
- 多個同名的,跨越相鄰行或列的單元稱為網格區塊(grid area)。非矩形的網格區塊是無效的。
- 網格區塊會影響到網格線。每個區塊的起始網格線,會自動命名為區塊名-start,終止網格線自動命名為區塊名-end。上面例子中,第一行第3、4列間的網格線自動命名為
a-end
和b-start
,水平網格線亦同理。 - 網格的命名並不會馬上影響網格項的顯示,需要使用專案屬性指定其位置才可以,專案屬性下面會講到。
2.3 grid-template
grid-template屬性是grid-template-columns、grid-template-rows和grid-template-areas這三個屬性的合併簡寫形式。
語法是 grid-template: <'grid-template-rows'> / <'grid-template-columns'>
.container {
display: grid;
width: 100%;
height: 200px;
grid-template: [header-left] "head head" 30px [header-right]
[main-left] "nav main" 1fr [main-right]
[footer-left] "nav foot" 30px [footer-right]
/ 120px 1fr;
}
先寫行屬性,再寫列屬性,中間用 /
隔開,從易讀性考慮,不建議這樣寫。
3. grid-gap
grid-row-gap 屬性是用來設定網格行與行之間的間隙,grid-column-gap 屬性是用來設定網格列與列之間的間隙。
.container{
display: grid;
grid-template-columns: repeat(auto-fit, 200px);
grid-template-rows: auto auto;
grid-row-gap: 20px;
grid-column-gap: 10px;
}
上面的程式碼設定列間隙為10px,行間隙為20px。
grid-gap是 grid-row-gap 和 grid-column-gap的簡寫形式,語法如下:
grid-gap:<row-gap> <column-gap>
如果省略了第二個值,瀏覽器認為第二個值等於第一個值。
根據最新標準,上面三個屬性名的grid-字首已經刪除,grid-column-gap和grid-row-gap寫成column-gap和row-gap,grid-gap寫成gap。
但是為了相容瀏覽器,比如火狐52-61,還需要使用帶有字首的屬性。
4.1. justify-items和align-items
justify-items 定義了網格佈局中專案的水平對齊方式,align-items 定義了豎直對齊方式。
這個與flex佈局的有些區別,flex佈局的對齊方式分主軸和交叉軸,主軸方向的改變影響屬性作用的方向。而grid佈局是二維的,行列方向是固定的,所以說到 justify 一定就是指行(水平)方向,align就是指列(豎直)方向。
屬性值:
- start:內容與網格區域的左端對齊
- end: 內容與網格區域的右端對齊
- center: 內容位於網格區域的中間位置
- stretch: 內容寬度佔據整個網格區域空間(預設值)
上圖顯示了justify-items不同取值的結果,align-items與justify-items效果一樣,只是作用的方向不同。
4.2. place-items
place-items屬性是align-items屬性和justify-items屬性的合併簡寫形式。
語法是 place-items: <align-items> <justify-items>;
如果省略第二個值,則瀏覽器認為與第一個值相等。
.container{
display: grid;
grid-template-columns: repeat(auto-fit, 200px);
grid-template-rows: auto auto;
place-items: center center;
}
有了這個屬性,水平垂直居中就很容易了。
5.1. justify-content和align-content
justify-content定義了網格容器中,網格區域在水平方向上的對齊方式,align-content定義了網格區域在豎直方向上的對齊方式。
屬性值比items要多:
- start:網格區域與容器的左端對齊
- end: 網格區域與容器的右端對齊
- center: 網格區域位於容器的中間位置
- stretch: 網格區域佔據整個容器空間(預設值)
- space-around:網格項之間設定等寬的間隙,與容器邊框的間隙是項之間間隙的一半
- space-between: 網格項之間設定等寬的間隙,與容器邊框沒有間隙
- space-evenly:網格項之間和與容器邊框設定等寬的間隙
與items一樣,上圖顯示了justify-content不同取值的結果,align-content與justify-content效果一樣,只是作用的方向不同。
5.2. place-content
place-content屬性是align-content屬性和justify-content屬性的合併簡寫形式。
語法是 place-content: <align-content> <justify-content>;
如果省略第二個值,則瀏覽器認為與第一個值相等。
.container{
display: grid;
grid-template-columns: repeat(auto-fit, 200px);
grid-template-rows: 100px 100px;
place-content: space-around space-evenly;
}
6. grid-auto-columns和grid-auto-rows
指定自動生成的網格軌道的大小。
當定義的網格不夠容納所有網格項,多出的網格項另起一行排列,或者給某一個網格項指定到定義好的網格區域的外部,這個時候,瀏覽器會自動生成多餘的網格,以便放置專案。
grid-auto-columns和grid-auto-rows就可以用來定義這些自動生成的多餘的網格的大小。
.container{
width: 500px;
height: 400px;
display: grid;
grid-template-columns: 40px auto 50px 40px;
grid-template-rows: 200px auto;
grid-auto-columns: 50px;
grid-gap: 5px;
}
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
</div>
如上面的程式碼所示,定義的網格是2行4列一共8個單元格,但是網格項有10個,所以最終生成的網格是3行4列,grid-auto-columns: 50px;
讓最後一行的行高為50px。
grid-auto-columns和grid-auto-rows的預設值為auto
。
7. grid-auto-flow
屬性控制著自動佈局演算法怎樣運作,精確指定在網格中被自動佈局的元素怎樣排列。
語法為 grid-auto-flow: [ row | column ] || dense
屬性值
- row: 指定自動佈局演算法按照通過逐行填充來排列元素,在必要時增加新行。(預設值)
- column:指定自動佈局演算法通過逐列填充來排列元素,在必要時增加新列。
- dense: 指定自動佈局演算法使用一種“稠密”堆積演算法,如果後面出現了稍小的元素,則會試圖去填充網格中前面留下的空白。
dense的意思即填充元素的時候,輪到一個元素了,發現這個格子放不下了,這個元素就被放到了新一行,如果沒有dense的話這個格子就空著了,加上dense的話,這個格子就會找其它能放下的元素放在這裡。
這樣做會填上稍大元素留下的空白,但同時也可能導致原來出現的次序被打亂。
博主不建議使用隱式的網格,即不建議使子元素超出定義的網格區域,也不建議使用grid-auto-flow,尤其dense屬性值,會讓佈局變得難以控制。
專案屬性
1.1. grid-column-start和grid-column-end和grid-row-start和grid-row-end
這四個屬性用來指定網格項在網格中的位置。從意思上就很明確。
- grid-column-start:專案左邊框的位置
- grid-column-end:專案右邊框的位置
- grid-row-start:專案上邊框的位置
- grid-row-end:專案下邊框的位置
可以指定的有網格線數字(1、2、3...的順序)、網格線名稱(之前命過名的話)、span(跨越)
語法為: <name> | <number> | span <number>
.container{
width: 600px;
height: 400px;
display: grid;
grid-template-columns: 200px 1fr;
grid-auto-rows: 80px 1fr 1fr;
grid-gap: 10px;
}
.item {
background: skyblue;
}
.toolbar{
grid-column-start: 1;
grid-column-end: 3;
}
.tree{
grid-row-start: 2;
grid-row-end: 4;
}
<div class="container">
<div class="item toolbar">toolbar</div>
<div class="item tree">tree</div>
<div class="item table">table</div>
<div class="item subtable">subtable</div>
</div>
上面的程式碼所示的就是一個典型的佈局,通過定義toolbar元素和tree元素的開始結束位置,達到佔用多個單元的目的。
使用span
關鍵字也可以實現,span
表示"跨越",即左右邊框(上下邊框)之間跨越多少個網格。
.toolbar{
grid-column-start: 1;
grid-column-end: span 2;
}
.tree{
grid-row-start: 2;
grid-row-end: span 2;
}
1.2. grid-row和grid-column
grid-row是grid-row-start和grid-row-end的簡寫形式。
grid-column是grid-column-start和grid-column-end的簡寫形式。
語法為:<start-line> / <end-line>
.toolbar{
grid-column: 1 / span 2;
}
.tree{
grid-row-start: 2 / span 2;
}
2. grid-area
grid-area屬性指定專案放在哪一個區域。
我們肯定還記得前面的這個屬性grid-template-areas
,給容器劃分割槽域並命名,命名完成以後,使用grid-area
屬性就可以指定專案放到哪裡了。
還是剛才那個典型佈局,這次我們用grid-area
屬性來試試。
.container{
width: 600px;
height: 400px;
display: grid;
grid-template-columns: 200px 1fr;
grid-auto-rows: 80px 1fr 1fr;
grid-gap: 10px;
grid-template-areas:
"toolbar toolbar"
"tree table"
"tree subtable";
}
.item {
background: skyblue;
}
.toolbar{
grid-area: toolbar;
}
.tree{
grid-area: tree;
}
<div class="container">
<div class="item toolbar">toolbar</div>
<div class="item tree">tree</div>
<div class="item table">table</div>
<div class="item subtable">subtable</div>
</div>
可以看到,效果跟剛才是一樣的。
我們需要注意的是:
- 我們給容器劃分割槽域,但是網格是不變的。
- 如果多個專案放在同一個位置,這些專案會重疊,可以使用z-index指定哪個在上面顯示。使用這個功能實現選項卡的切換也很方便。
3.1 justify-self和align-self
justify-self設定元素中內容的水平對齊方式。align-self設定元素中內容的豎直對齊方式。
- start:內容與網格項的左端對齊
- end: 內容與網格項的右端對齊
- center: 內容位於網格項的中間位置
- stretch: 內容寬度佔據整個網格項空間(預設值)
3.2 place-self
place-self屬性是align-self屬性和justify-self屬性的合併簡寫形式。
語法為:<align-self> <justify-self>
.item {
place-self: center center
}
如果省略第二個值,place-self屬性會認為這兩個值相等。
結束
以上就是grid佈局的簡單介紹~~
參考內容:
mdn api: https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Grid_Layout
阮一峰CSS Grid 網格佈局教程:http://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html