CSS Masonry Layouts【一】之 multi-columns

網易考拉前端團隊發表於2017-09-14

Masonry Layouts —— 瀑布流佈局,核心是一個網格佈局,每行包含的內容列表的高度是不可控的,並且,每個內容列表呈堆疊狀排列。稱作瀑布流,最關鍵的是--各堆疊間沒有多餘的間距差(將整個佈局看做一個大的容器,最新進來的內容元素,永遠在高度最短的那一列上)。具體如下圖所示:

注:上圖是 二次元社群GACHA 的插畫頻道,該瀑布流外掛基於NEJ,互動要求是:每一列固定寬度,根據頁面大小顯示不同的列,頁面寬度,重排,預載入一屏,滾動載入。設計的思路是:

  1. 計算列數:根據當前頁面(容器)寬度,計算一行可以排放幾個元素
  2. 初始堆疊:建立列堆疊陣列,用於存放各個列堆疊的高度
  3. 最小索引:得到列堆疊陣列中的最小值和其對應索引
  4. 元素定位:所有元素 absolute 定位,設定後續加入元素的 top 值為列堆疊陣列中的最小值,同時設定它的 left 值為該索引對應列的 left 值
  5. 更新堆疊:更新列堆疊陣列中該索引下元素的值( no.4 中的 top 值加元素本身的的高度)
  • 注:上面略去了對資料的預處理(包括圖片的等比縮放以及屬性的二次處理等)以及滾動載入的處理過程,對於預載入一屏,由於元素高度的不可控性,只能根據瀑布流元素的平均高度行預估計,然後推算出一屏需要元素的範圍,然後請求相應數量。

簡化版應該是下面這樣的:

但是,這樣處理,表現層的東西依賴 javaScript 來處理,有點多餘(當時確實是唯一的辦法),能不能用樣式來搞定呢?

首先,會想到 float 或者 inline-block ,但是它們都沒辦法很好的控制列表之間的間距。最終得到的效果就像下面這樣:

那,除此之外,就沒有單純用 css 可以搞定的方法了嗎?近幾年,css 的技術更新頻繁,出現了很多新的佈局方法:multi-columnsFlexboxGrid。用上面提到的佈局方法能否實現瀑布流呢?

multi-columns

multi-columns 產生之初,是用來實現文字多列排列,類似報紙、雜誌的文字排列方式。multi-columns佈局方式跟瀑布流的有些類似:

demo

三列:

四列:

猛一看很完美。但是,與使用 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 瀑布流佈局,適用於:

  1. 元素不存在優先順序,或者優先順序要求較低
  2. 元素高度差異不明顯(防止出現大片空白區域)
  3. 不相容低版本瀏覽器(最重要的)

除了 multi-columnsFlexbox 以及 Grid 也可以運用到瀑布流佈局中來。未完,待續。。。

相關文章