Masonry Layouts —— 瀑布流佈局,核心是一個網格佈局,每行包含的內容列表的高度是不可控的,並且,每個內容列表呈堆疊狀排列。稱作瀑布流,最關鍵的是--各堆疊間沒有多餘的間距差(將整個佈局看做一個大的容器,最新進來的內容元素,永遠在高度最短的那一列上)。具體如下圖所示:
注:上圖是 二次元社群GACHA 的插畫頻道,該瀑布流外掛基於NEJ,互動要求是:每一列固定寬度,根據頁面大小顯示不同的列,頁面寬度,重排,預載入一屏,滾動載入。設計的思路是:
- 計算列數:根據當前頁面(容器)寬度,計算一行可以排放幾個元素
- 初始堆疊:建立列堆疊陣列,用於存放各個列堆疊的高度
- 最小索引:得到列堆疊陣列中的最小值和其對應索引
- 元素定位:所有元素
absolute
定位,設定後續加入元素的top
值為列堆疊陣列中的最小值,同時設定它的left
值為該索引對應列的 left 值 - 更新堆疊:更新列堆疊陣列中該索引下元素的值( no.4 中的
top
值加元素本身的的高度)
- 注:上面略去了對資料的預處理(包括圖片的等比縮放以及屬性的二次處理等)以及滾動載入的處理過程,對於預載入一屏,由於元素高度的不可控性,只能根據瀑布流元素的平均高度行預估計,然後推算出一屏需要元素的範圍,然後請求相應數量。
簡化版應該是下面這樣的:
但是,這樣處理,表現層的東西依賴 javaScript
來處理,有點多餘(當時確實是唯一的辦法),能不能用樣式來搞定呢?
首先,會想到 float
或者 inline-block
,但是它們都沒辦法很好的控制列表之間的間距。最終得到的效果就像下面這樣:
那,除此之外,就沒有單純用 css
可以搞定的方法了嗎?近幾年,css
的技術更新頻繁,出現了很多新的佈局方法:multi-columns
、Flexbox
、Grid
。用上面提到的佈局方法能否實現瀑布流呢?
multi-columns
multi-columns
產生之初,是用來實現文字多列排列,類似報紙、雜誌的文字排列方式。multi-columns
的列佈局方式跟瀑布流的有些類似:
三列:
四列:
猛一看很完美。但是,與使用 js 實現對比之下:
multi-columns
的元素是縱向排列的(在對元素先後次序有要求的情況下不理想)- 隨著容器寬度變化,明顯發現出現比較大的空白區域(從三列到四列)
第一個問題,multi-columns
的這種佈局方式,決定了只能縱向排列;對於第二個問題:
multi-columns 簡略佈局思想
首先,只有在多列元素集含有塊級元素、並且避免在元素內部斷行併產生新列的時候,才會涉及到佈局,上面的瀑布流例子,要是不避免在元素內部斷行併產生新列,將會是這樣的:
只有將屬性 break-inside
設定為 avoid
,才會有塊級元素的效果。
回到上面說到的空白區域的問題,multi-columns
的整體佈局會受到幾個因素的影響:
總體而言,優先順序:自身屬性 > 容器屬性。
當容器的高度小於按照 column-count
佈局後的列的高度,會發生元素斷裂、跨列的現象;當容器的高度大於按照 column-count
佈局後的列的高度,單個列的高度會由最優佈局演算法生成。
所謂最優佈局演算法,簡單來說,就是自適應:
- 首先取
column-count
,如果元素(block)個數不超過column-count
,佈局成一橫排;
- 若是元素(block)個數超過
column-count
,首先在第一列增加 block 元素,而後以第一列的高度為標準,來填充後續各列(此時會發生列填充不滿的情況);
- 若是之後元素中發現一個高度較高的X元素,對於佈局的調整會以這個較高的X元素為分界線,不會將後面的低高度元素排列到X元素之前:
就會出現較大空白區域的情況。
所以,出現空白區域的根本原因是:multi-columns
佈局的特點是按列布局、順序計算、順序排列,前面有較大空白區域,不會用後續元素去填補。
想要具體瞭解 multi-columns
佈局,請參考:
總結:
multi-columns
瀑布流佈局,適用於:
- 元素不存在優先順序,或者優先順序要求較低
- 元素高度差異不明顯(防止出現大片空白區域)
- 不相容低版本瀏覽器(最重要的)
除了 multi-columns
, Flexbox
以及 Grid
也可以運用到瀑布流佈局中來。未完,待續。。。