【CSS】519- grid-auto-flow深入理解
- 2020 年 3 月 3 日
- 筆記
原文:https://www.zhangxinxu.com/wordpress/2020/01/css-grid-auto-flow/
一、grid-auto-flow出現的背景
Grid布局要想玩得666,grid-auto-flow
是繞不開的需要深度掌握的CSS屬性。
Grid布局就像農村土改分土地。
政府會把土地分成一塊一塊的,然後這一塊是張三的,那一塊是王二的。
這個劃分就是通過grid-template
屬性。
比方說:
.fileds { display: grid; grid-template: 1fr 1fr / 1fr 1fr; }
就是把這塊土地分成兩行,兩列4塊田地。
然而應用到具體的場景,事情往往就出乎意料的複雜。
例如:
- 如果日後村裡搬遷了幾戶新住戶,那該怎麼劃分?
- 4塊田地分給張三和王二,你說是橫的兩塊地給張三呢,還是豎的兩塊地給張三?
- 孤寡老人李大爺過世了,他的田地是否可以分給後面的人?
這些意料之外的場景單靠grid-template
屬性肯定捉襟見肘,此時,就需要grid-auto-flow
屬性出馬。
grid-auto-flow
屬性可以定義Grid布局中每一個Grid子項「自動流動」狀態。
二、了解grid-auto-flow的語法
grid-auto-flow: [ row | column ] || dense
因此,下面這些寫法都是合法的:
grid-auto-flow: row; grid-auto-flow: column; grid-auto-flow: dense; grid-auto-flow: row dense; grid-auto-flow: column dense;
其中:
- row
- 多的格子一行一行陳列。默認值。
- column
- 多的格子一列一列排列。
- dense
- 多的格子空白填充。
各個關鍵字值具體什麼意思,我們還得看案例才能明白。
三、row和column屬性值基礎
1. 默認值row
從天上掉下來一個寶貝容器,定睛一看,容器元素標籤名是zxx-grid
,好巧,正好應用的CSS聲明就是display:grid
,如下:
zxx-grid { display: grid; }
然後很巧的是還有若干子元素,如下:
<zxx-grid> <zxx-item>格子1</zxx-item> <zxx-item>格子2</zxx-item> <zxx-item>格子3</zxx-item> <zxx-item>格子4</zxx-item> <zxx-item>格子5</zxx-item> <zxx-item>格子6</zxx-item> <zxx-item>格子7</zxx-item> <zxx-item>格子8</zxx-item> <zxx-item>格子9</zxx-item> </zxx-grid>
<zxx-grid>
元素除了應用了display:grid
沒有任何其他CSS,因此,所有的子元素的grid-auto-flow
「自動流動」的狀態是其默認值。
grid-auto-flow
的默認值是row
,row
的中文意思是「行」,也就是所有的子元素一行一行顯示,優先水平排列。
於是,最終的網格輪廓結構會是下圖這樣:

更進一步
如果我們使用grid-template
屬性指定Grid的列數為2列,如下:
zxx-grid { display: grid; grid-template: auto / 1fr 1fr; line-height: 40px; }
大家就會看到Grid子元素的排列流向是下面這樣的,先是水平排列,然後再到下一行再水平排列,一直到最後不斷循環:

大家可能覺得理所當然就應該這樣排列,太天真了!

大家稍後對比column
屬性值的效果就知道Grid子項的排列順序並不是一成不變的了。
2. 關鍵字值column
如果我們設置grid-auto-flow
的屬性值是column
,column
的中文意思是「列」,則表示「自動流動」狀態的子元素全部都一列一列顯示。
假設容器元素CSS如下:
zxx-grid { display: grid; grid-auto-flow: column; }
則幾個子元素的布局效果會是下面截圖這樣,全部縱排了:

發現沒有?使用grid-auto-flow
屬性可以非常簡單實現子元素個數不固定的等分佈局效果,就是值設置為column
就可以了。
更進一步
這裡,我們同樣指定我們的Grid布局是2行,CSS代碼如下:
zxx-grid { display: grid; grid-template-rows: 1fr 1fr; grid-auto-flow: column; line-height: 40px; }
大家就會發現Grid子元素的排列流向和row
屬性值就不一樣了:

是優先垂直方向排列,然後再到下一列往下排列,一直循環往複到最後一列。
由此,我們可以得出結論,grid-auto-flow
屬性會影響Grid布局的排列順序。
3. 排序與布局實例
有人在微信粉絲群裏面問了下面這個問題,實現下圖所示布局:

這個布局效果,最簡單的方法就是用浮動3個圖片都設置float:left
就可以了,就這麼簡單。
但是如果我們這裡的圖片不是3個,而是5個(如下圖),那麼浮動就無能為力了。

此時,則可以試試Grid布局,讓第一個子項橫跨左側兩個格子,然後後面4個格子按照grid-auto-flow:column
的流向排列即可。
HTML代碼如下:
<zxx-grid> <zxx-item><img src="./xugou-1.jpg"></zxx-item> <zxx-item><img src="./xugou-2.jpg"></zxx-item> <zxx-item><img src="./xugou-3.jpg"></zxx-item> <zxx-item><img src="./xugou-4.jpg"></zxx-item> <zxx-item><img src="./xugou-5.jpg"></zxx-item> </zxx-grid>
CSS代碼如下:
zxx-grid { display: grid; grid-auto-flow: column; grid-template: 1fr 1fr / 1fr 1fr 1fr; grid-template-areas: "a b d" "a c e"; grid-gap: 6px; } zxx-item:first-child { grid-area: a; }
則有如下圖所示的布局效果:

而且整個布局是彈性變化的,如下視頻所示(不動可以點擊播放):
對吧,布局效果還是很酷的。
最後,測試下grid-auto-flow:column
在這個例子中所起的作用,我們打開控制台,注釋掉grid-auto-flow:column
這句CSS聲明,則我們會得到下圖所示的布局效果,圖2到圖5都是水平平鋪呈現,這個效果Float浮動就可以實現。

對應的Demo頁面
上面的例子有專門的demo演示頁面,您可以狠狠的點擊這裡:grid布局實現圖像A|B+C布局demo
//zxx: Chrome瀏覽器的圖片height:100%似乎有bug,Firefox瀏覽器沒有這個問題
四、row和column屬性值深入
第三小節演示的幾個案例都是我們所有的格子都已經規定好的,但是實際開發,Grid格子的數量可能是動態的,無論是grid-template
還是grid-template-areas
往往就沒法兼顧全部的子元素,此時,Grid布局又該如何表現?
為了更進一步展示關鍵字值column
的效果,我們來看一個稍微再複雜一點的例子:
我們設定網格模板是 2 x 2,也就是前4個元素按照指定網格陳列,後面的子元素auto-flow自由流動。相關CSS如下:
zxx-grid { display: grid; grid-template: 1fr 1fr / 1fr 1fr; grid-auto-flow: column; }
則最終效果如下:

為什麼會有上圖這樣的效果呢?
首先大家一定要搞清楚一點,1fr 1fr
並不等於50% 50%
,雖然很多時候表現是一樣的,但只是grid格子正好和設定數量一致的時候。1fr 1fr
更準確的含義是,可用剩餘空間分別50% 50%
。
在本例中,格子5~格子9屬於「放任自流」的盒子,因為grid-template:1fr 1fr / 1fr 1fr
只指定了4個格子的尺寸,那剩餘的5個格子怎麼辦呢?
那就是grid-auto-flow
屬性大發神威的時候。
這裡grid-auto-flow
設置的屬性值是column
,也就是沒有指定模板的剩餘5個格子垂直按需排列。如下圖標註:

由於沒有指定寬度,因此,格子的尺寸就fit-content
,根據內容的尺寸來。
在實際開發的時候,我們往往只要指定好垂直列的個數和寬度分配比,無論多少個grid子元素,都會依次排列好,其最底層最根本的原因其實是grid-auto-flow:row
在起作用。
例如:
zxx-grid { display: grid; grid-template-columns: 1fr 1fr; }
效果是下面這樣,9個格子了,一個一個排的非常整齊,因為「自動流動」默認是水平的。

五、不太好懂的dense屬性值
最後,再講講dense
屬性值。
dense
單從字面含義是不太好理解的,dense
的中文意思是「密集的」,「稠密的」,「濃密的」。
密集的是樹林,稠密的是奶昔,濃密的是頭髮,跟Grid布局好像不搭邊吧。
實際上,這裡dense
應該用一種更感性的方式去體會這個詞的含義。
在本文一開始提到了一個引子「孤寡老人李大爺過世了,他的田地是否可以分給後面的人?」
比如說村裡9戶人家,每一戶都分得了一塊田地,大家的田地都是緊密相連的。
結果孤寡老人李大爺和王大爺相繼去世。於是,就有兩塊田地是空缺的,因為有空缺,所以這個時候,如果我們使用無人機從上方拍一個照片,則田地是稀疏的,不是緊密的。
這個時候,村裡又來了兩戶新人家,也要分田地。
如果是dense
,則優先分配之前李大爺和王大爺留下的空缺的土地,因為這樣會讓整片田地沒有空缺,是「密集的」,「緊密的」。
grid-auto-flow:dense
也是類似的意思。
dense理解案例
我們可以人為製造出稀疏布局結構(前面幾個Grid格子留空),代碼如下:
zxx-grid { display: grid; grid-template-columns: 1fr 1fr; } zxx-item:first-child { grid-column-start: 2; }
效果如下,第一個格子空缺了:

如果我們希望第一個格子被充分利用,讓整個排列是緊密相連的,則可以使用dense
關鍵字值。
zxx-grid { display: grid; grid-template-columns: 1fr 1fr; grid-auto-flow: dense; } zxx-item:first-child { grid-column-start: 2; }
此時瀏覽器的渲染表現是怎樣的呢?請看下圖:

原本流出來的第1個格子的窟窿,被格子2給填上了。
這個Grid布局又是「緊密的」了,這就是dense
屬性的作用。
dense
實際開發的時候有什麼作用呢?
比方說我希望某兩個相鄰的格子視覺順序和DOM順序是相反的,也就是兩者調換位置,則可以使用dense
實現。
其他
dense
可以和row
以及column
這兩個關鍵字只是同時使用,例如:
grid-auto-flow: row dense; // 等同於dense grid-auto-flow: column dense;
六、最後的總結么么噠
本文雖然只有5000字,不過花的時間還挺多,算上今天,斷斷續續寫了一周。

為什麼這篇文章跨度時間比較長呢?除了用心做demo,用心創作外,還有其他兩方面主要原因:
- 邊研究邊測試邊寫,結果發現了自己一開始想當然的錯誤理解,然後不少內容重新組織推翻重來。因此可見,寫文章其實對深度學習、了解細節,理清思路非常有幫助,是非常好的一種學習方法。
- 現在上年紀了,體力沒以前好了。以前都是寫到1點,這種程度的文章2~3天就完成。現在頂不住了,12點左右就困得不行,關機睡覺去了,所以寫作時間跨度就更長了。
CSS文章已經連更十幾篇了,小本本上還有好幾篇CSS文章要寫的。
光CSS基礎API只是更新迭代的東西就這麼多,再考慮到吃了激素一路狂奔年年暴走的ES規範,現在的前端開發想成為通才基本上不可能了,只能選擇合適的領域,一點一點發光發熱吧。
哎呀呀,就說這麼多了。
用心之作,歡迎分享!
行文匆忙,如果文章有表述不準確的地方,歡迎指正!