你知道的越多,你不知道的越多
點贊
再看,手留餘香,與有榮焉javascript
2019年終歲尾,最近對佈局相關的內容比較有興趣,在此整理一下和瀑布流相關的使用場景以及多種實現方案。css
瀑布流
又稱瀑布流式佈局,是一種比較流行的頁面佈局方式,專業的英文名稱爲[Masonry Layouts
]。與傳統的分頁顯示不一樣,視覺表現爲良莠不齊
的多欄佈局,最先是由Pinterest首先運用。html
無圖無真相:前端
如圖所示,網頁上呈現良莠不齊
的多欄佈局,圖片等寬不等高
,根據圖片原比例縮放直至寬度達到固定的要求,每行排滿後,後面的元素依次添加到其後,視覺上顯得錯落有致不拘一格。java
優勢以下:css3
從體驗的心理講,女性是一種逛街數小時都不須要停歇的生物,一眼望不到頭的瀑布流契合了這種心理。瀑布流的圖片就像商品,就像逛街、就像掃貨。女性只要不斷往下拉伸頁面,就像置身在一條沒有盡頭的購物街,沒有層高限制的商場中同樣。傳統佈局中的下一頁就是打斷,比如男友輕聲在耳邊說了句:休息一下吧,我累了……結果不言而喻~git
缺點以下:github
根據瀑布流的優缺點,咱們不可貴出在什麼狀況下選擇瀑布流是合理的選擇:瀏覽器
內容以圖片爲主的時候
,瀑布流是更好的選擇。圖片佔用空間比較大,而且大腦理解的速度相比理解文字要快,短期內能夠掃過的內容不少,因此若是用分頁顯示的話用戶務必會頻繁的翻頁,影響沉浸式的體驗,而瀑布流能夠解決這個問題。微信
信息與信息之間相對獨立時
,瀑布流是更好的選擇。若是信息關聯性強,用戶務必會進行大量的回溯操做去查看以前或者以後的信息,相反,若是信息相對獨立的話,可使用瀑布流,讓用戶同時接受來自不一樣地方的信息。
信息與搜索匹配比較模糊時
,瀑布流是更好的選擇。瀑布流給人的直觀印象,就是同時顯示的信息與用戶搜索的匹配度大體同樣,而分頁顯示的直觀印象則是越靠上的信息被認爲與用戶的搜索越匹配。所以,當信息與搜索匹配度沒有明顯區分度時,能夠採用瀑布流。
用戶目的性不強的時候
,瀑布流是更好的選擇。若是用戶有特定須要查找的信息,分頁查找定位更方便,而當目的性較弱的時候,瀑布流能夠增長用戶停留的時間和意想不到的收穫。
一般Multi-column
用於文本的分列:
.container {
column-count: 3;
}
複製代碼
multi-column
佈局中子元素的排列順序是先從上往下
再從左至右
。
根據這個特性,咱們就能夠用來實現瀑布流
。
multi-column
實現瀑布流
主要依賴如下幾個屬性:
column-count
: 設置共有幾列column-width
: 設置每列寬度,列數由總寬度
與每列寬度
計算得出column-gap
: 設置列與列之間的間距column-count
和column-width
均可以用來定義分欄的數目,並且並無明確的優先級之分。優先級的計算取決與具體的場景。
計算方式爲:計算column-count
和column-width
轉換後具體的列數,哪一個小就用哪一個。
一個圖片&文字的例子:
<div class="masonry">
<div class="item">
<img src="..."/>
<span class="title">...</span>
</div>
<div class="item">
<img src="..."/>
<span class="title">...</span>
</div>
<!-- more items-->
</div>
複製代碼
.masonry{
column-count: 3;
column-gap: 10px;
}
.masonry .item{
border:1px solid #999;
margin-bottom: 10px;
}
.masonry .item img{
width: 100%;
}
複製代碼
效果以下:
咱們能夠看到,雖然實現了瀑布流
的效果,但奇怪的是例子中前兩列的最後一個元素的文本內容
被自動斷開
,一部分在當前列尾,一部分在下一列的列頭。
個人理解是multi-column
佈局會將其內的元素自動進行流動和平衡,儘量保證每列的高度趨於相同,因此會將其內的文本階段分佈在兩列內。
而這種展現方式無疑是咱們不但願看到的,咱們但願的是每一個元素都是獨立的,先後不斷開,此時咱們須要使用break-inside
來實現。
break-inside: auto | avoid
修改一下以前的例子:
.masonry .item{
break-inside: avoid;
}
複製代碼
效果以下:
效果實現了,但因爲multi-column
佈局中子元素的排列順序是先從上往下
再從左至右
,因此這種方式僅適用於數據固定不變的狀況,對於滾動加載更多等可動態添加數據的狀況就並不適用了。
Grid佈局
是最強大的 CSS 佈局方案。
它將網頁劃分紅一個個網格,能夠任意組合不一樣的網格,作出各類各樣的佈局。之前,只能經過複雜的 CSS 框架達到的效果,如今瀏覽器內置了。
上圖這樣的佈局,就是 Grid 佈局的拿手好戲,所以,咱們就能夠用Grid
來實現瀑布流
。
爲實現瀑布流
先介紹如下幾個屬性:
display
:設置爲grid
指明當前容器爲Grid佈局
grid-template-columns
: 定義每一列的列寬grid-template-rows
: 定義每一行的行高column-gap
:用於設置列間距grid-template-columns
和grid-template-rows
,可使用絕對單位,也可使用百分比。而且爲了表示比例關係,Grid
佈局提供了fr
關鍵字,若是設置1fr
和2fr
,表示後者是前者的兩倍。
根據以上幾個屬性,先寫一個例子出來,看看效果:
<div class="masonry">
<div class="item"></div>
<!-- more items-->
</div>
複製代碼
.masonry{
display: grid;
grid-template-rows: 1fr 1fr 1fr; // 分爲3行
grid-template-columns: 1fr 1fr 1fr; // 分爲3列
column-gap:5px; // 列間距5px
}
複製代碼
效果以下:
咱們看到高度不一樣的div塊分佈在每個單元格內,但尚未實現瀑布流
的效果。
爲實現瀑布流
再介紹幾個屬性:
grid-row-start
:上邊框所在的水平網格線
grid-row-end
:下邊框所在的水平網格線
grid-column-start
:左邊框所在的垂直網格線
grid-column-end
:右邊框所在的垂直網格線
那麼什麼是網格線
呢?
劃分網格的線,稱爲網格線
。水平網格線劃分出行,垂直網格線劃分出列。
正常狀況下,n行
有n + 1
根水平網格線,m列
有m + 1
根垂直網格線,好比三行就有四根水平網格線。
上圖是一個 4 x 4 的網格,共有5根水平網格線和5根垂直網格線。
這4個屬性可接收以下屬性:
auto
:表示自動放置自定義名稱
:能夠給予網格線一個名稱,並在此處引用(本文並不涉及)網格線索引
: 表明第幾條網格線(從1開始)span + 數字
: 表示上下邊框或左右邊框跨越多少網格來看看這個網格線
有什麼用處
爲方便查看,咱們讓例子中的每一個div塊高度修改成100%,並將樣式代碼修改成:
.item{
height:100%;
}
.item:first-child{
grid-row-start:1;
grid-row-end:span 2;
}
複製代碼
咱們對Grid
佈局中的第一項添加了grid-row-start:1
和grid-row-end:span 2
,令其上邊框位於1水平網格線,下邊框距上邊框跨越2個水平網格線。從效果上看來,是否是有點像瀑布流
了呢!
在以前的例子中,咱們分別指定了grid-template-columns
和grid-template-rows
用於定義幾行幾列,因爲行列數的肯定,其內的每一個單元格的寬高也被肯定了,而實際的瀑布流
佈局中,寬度是固定的,而高度是動態的,而且具體的行數也是沒法在開始時肯定的,因此咱們須要在Grid
佈局中不指定行高(grid-template-rows)。
介紹另外一個屬性:
grid-auto-rows
:用來設置多餘網格的行高結合剛纔說的Grid實現的瀑布流佈局中,不設置行高(grid-template-rows),此時設置grid-auto-rows
後,全部單元格的高度均爲grid-auto-rows
指定的值。
因爲grid-row-start
和grid-row-end
能夠指定單元格的上邊距和下邊距位置,也就是說能夠將單元格的高度拉伸,而原有高度由grid-auto-rows
決定,咱們僅需將grid-auto-rows
設置一個很小的值,好比10px
,而後對其進行拉伸將其高度指定爲真實高度,每個單元格都作以下操做,那麼瀑布流就實現了~
假設第一個單元格內容真實高度爲100px,因爲grid-auto-rows:10px
,那麼咱們能夠這樣設置:
.item1{
grid-row-start:'auto';
grid-row-end:span 10;
}
複製代碼
假設第二個單元格內容真實高度爲150px,因爲grid-auto-rows:10px
,那麼咱們能夠這樣設置:
.item2{
grid-row-start:'auto';
grid-row-end:span 15;
}
複製代碼
固然了,在實際狀況中,瀑布流
更多的是爲圖片的展現而服務的,而且因爲圖片是異步請求加載,只有在加載完成後才能獲取圖片的真實寬高,因此不得不使用JS來動態將單元格高度進行拉伸。
僞代碼以下:
//image-dom
let img = document.getElementsByTagName('img')[0];
//image-dom 當前寬度
let width = img.width;
let image = new Image();
image.src = 'xxxx.img';
image.onload = function(){
//圖片原寬
let w = image.width;
//圖片原高
let h = image.height;
//image-dom的真實高度(依據當前寬度及圖片真實寬高)
let height = Math.round(h * width / w)
//設置當前跨越幾個網格(每一個網格10px)
img.style.gridRowEnd = `span ${~~(height/10)}`
}
複製代碼
效果以下:
Flexbox
佈局到今天已是使用很是普遍的,也算是很成熟的一個特性。在此就再也不介紹Flexbox
佈局的相關內容,若是還有不是很瞭解的朋友,可參見阮一峯的《Flex 佈局教程:語法篇》
那接下來咱們就看Flexbox
怎麼實現瀑布流佈局。
此時,咱們須要將html結構設計成以下結構:
<div class="masonry">
<!-- 第一列 -->
<div class="column">
<div class="item"></div>
<!-- more items-->
</div>
<!-- 第二列 -->
<div class="column">
<div class="item"></div>
<!-- more items-->
</div>
<!-- 第三列 -->
<div class="column">
<div class="item"></div>
<!-- more items-->
</div>
</div>
複製代碼
上面代碼中div.masonry
表明當前瀑布流容器,div.column
表明每一列的容器,div.item
表明每一列中的每一項。
咱們須要將div.masonry
和div.column
都經過display:flex
將其設置爲Flex
容器。
不一樣的是瀑布流容器
主軸方向設置爲水平方向flex-direction:row
,列容器
主軸方向設置爲垂直方向flex-direction:column
.masonry {
display: flex; // 設置爲Flex容器
flex-direction: row; // 主軸方向設置爲水平方向
}
.column {
display: flex; // 設置爲Flex容器
flex-direction: column; // 主軸方向設置爲垂直方向
}
複製代碼
效果以下:
作瀑布流須要考慮幾方面大因素,圖片質量,圖片大小,加載速度,若是這些不能同時知足,會大大下降用戶體驗。我的以爲瀑布流對於觸屏終端體驗會更好一些。
本文總結了multi-column
、grid
、Flexbox
三種方式實現瀑布流,實現方案各有不一樣,從兼容性及易用性綜合考慮,仍是推薦使用Flexbox
的佈局實現方案。
本文介紹的瀑布流
佈局方案,本質上可稱爲豎向瀑布流
,篇幅有限,並未涉及橫向瀑布流
的內容,關於橫向瀑布流
的內容,會在接下來的文章中繼續總結,敬請期待。
歡迎關注微信公衆號
【前端小黑屋】
,每週1-3篇精品優質文章推送,助你走上進階之旅
同時歡迎加我好友,回覆
加羣
,拉你入羣,和我一塊兒學前端~