本篇文章帶大家了解瀑布流佈局,介紹一下三種可靠度JS方案,以及N種不太可靠CSS方案。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。
本著實用精神,我們今天來分享一下瀑布流佈局(昨天有個小兄弟問我怎麼做,我找了半天沒找到,啊原來寫在內網了)。
示範網址: http://www.lilnong.top/static/html/waterfall.html
比如說 花瓣網、蘑菇街 (我下面貼圖了), 這些網站在顯示內容的時候就使用了瀑布流佈局。
我們也想做一個展示我們設計稿(定寬,不定高)的頁面,瀑布流是很棒的一種方案。
瀑布流佈局其核心是基於一個網格的佈局,而且每行包含的項目列表高度是隨機的(隨著自己內容動態變化高度),同時每個項目列表以堆疊形式排列,最為關鍵的是,堆疊之間彼此之間沒有多餘的間距差存大。還是上圖來看看我們說的瀑布流佈局是什麼樣子。
網站 | #蘑菇街 | 花瓣網 | 京東 | VV |
---|---|---|---|---|
截圖 | ||||
##方案 | 分通道 | absolute |
也算是純CSS 方案吧,本質上來講是依賴文件流
,從左到右,從上到下。方案 | grid | inline | float | bootstrap-grid |
---|---|---|---|---|
#截圖 |
可以看到在文件流程佈局中有非常明顯的行的概念,當一個行被撐開就會留下空白,行與行不會重疊。這裡最魔性的就是 float 佈局了。
div.list // 设置 gird 或者 block,注意清除浮动 div.item // 设置为 inline 或者 float,使其能流动 img // 设置定宽,高度自适应,间距等。
.wrap-waterfall--grid img{vertical-align: top;width: 100px} .wrap-waterfall--grid .list{ display: grid; grid-gap: 10px; /* 可以看到,网格大小,占据位置是需要提前设定的 */ grid-template-columns: repeat(4, 1fr); grid-auto-rows: minmax(50px, auto); }
grid 在某些情況下會比 flex 好用。比如說需要突破行的限制,但是只適用於固定佈局,如下圖的佈局,如果不使用grid你會如何實現呢?
網傳有gird 實現瀑布流佈局的方案,但是我看了幾個他們不是色塊,就是圖片變形、裁剪,方案是用nth-child 定高,太恐怖了吧。
也是純CSS 方案,比較上面的方案而言,方案已經可以接受,只是還有部分問題。
方案 | columns | flex |
---|---|---|
截圖 |
天生支持,只需給父級設定即可
#absolute | |||
---|---|---|---|
#absolute取餘分通道 | 計算高度分通道#頭截圖 |
这里的方案就靠谱起来了,可以满足我们使用要求。
我们来回忆一下我们的需求:展示一些内容,内容有特性定宽,不定高。不定高一般是因为内容长度或者高度不一致导致的,常见内容又分为两种文字和图片。
文字的话,在没有异步字体的情况下,可以理解为同步就可以获取到盒子高度。
图片的话,因为加载是异步的,所以获取盒子的真实高度也是异步的。但是这里一般分为两种情况
无高度,那么可以通过onload来监听图片加载完成。等图片加载完成再去获取高度。
// 用于获取图片的真实高度 naturalHeight: 1180 // 用于获取图片的真实宽度 naturalWidth: 1200 //用户获取图片当前的渲染高度(会受 css 影响) height: 98 //用户获取图片当前的渲染宽度(会受 css 影响) width: 100 // 可返回浏览器是否已完成对图像的加载。如果加载完成,则返回 true,否则返回 fasle。 complete 属性 // 可以监听到图片加载完成的动作 onload
基于上面的内容,那我们可以先判断 complete 属性,
function getImageSize(img){ if(img.complete){ return Promise.resolve({ naturalHeight: img.naturalHeight, naturalWidth: img.naturalWidth, height: img.height, width: img.width, }) }else{ return new Promise((resolve, reject)=>{ img.addEventListener('load', ()=>{ resolve({ naturalHeight: img.naturalHeight, naturalWidth: img.naturalWidth, height: img.height, width: img.width, }) }) }) } } /* // 测试用例 el = document.createElement('img'); el.src = 'http://cors-www.lilnong.top/favicon.ico?'+Math.random() getImageSize(el).then(console.log).catch(console.error) setTimeout(()=>getImageSize(el).then(console.log).catch(console.error), 1000) */
因为普通的布局已经无法满足我们的需求,所以我们可以考虑通过 position: absolute
来使内容通过绝对定位来显示。
核心操作就是维护每个元素的 left、top,然后使用 left 和 top 去渲染到正确位置。
getListPosition(){ // 视口宽度 / 每列宽度 得出划分为几列 let col = this.screenWidth / this.itemWidth >> 0; var arr = []; for(var i = 0; i < col; i++) arr.push({ list: [], height: 0, }) // 遍历所有元素 this.listInfo.forEach((item,idx)=>{ // 找到最低的一列 var colIndex = 0; for(var i = 1; i < col; i++){ if(arr[colIndex].height > arr[i].height){ // colItem = arr[i] colIndex = i } } // 修改元素的信息 // 所属列 item.line = colIndex; // 计算之后的 top 距离 item.top = arr[colIndex].height+ 'px'; // 计算之后的 left 距离 item.left = colIndex * (this.itemWidth + 10) + 'px' // 累加操作 arr[colIndex].list.push(item); arr[colIndex].height += item.height + 10; }) return arr },
通过计算,我们可以到,瀑布流布局下每个元素的位置,通过绝对定位就可以实现。
因为上个方案用到了绝对定位,那么有没有不用绝对定位的方案呢?回到我们的问题点上 定宽,不定高,那我们完全可以通过分开渲染放弃 absolute 来实现。
jsGroupList(){ return this.list.reduce((s,n,idx)=>{ // 根据下标,直接分配所属列 s[idx % 4].push({idx: idx, item: n}) return s }, [[],[],[],[],]) },
看开头是实现类似的功能的,但是有一个弊端(快来评论区回复呀)。
因为上一个方案是按下标分类的,其实瀑布流是按高度分类的,所以我们分类条件换成最低的列。
jsGroupHeightList(){ var list = [ {height: 0, list: []},{height: 0, list: []}, {height: 0, list: []},{height: 0, list: []}, ] // 遍历每个元素 for(var i = 0; i < this.list.length; i++){ // 当元素有大小的时候在进行操作。 if(!this.listInfo[i].height) return list; // 默认第一个通道是最小高度列 var minHeightItem = list[0]; // 计算最小高度列 list.forEach(v=>{ if(v.height < minHeightItem.height) minHeightItem = v }) // 把新的元素高度累加到列中。 minHeightItem.height += this.listInfo[i].height // 把新的元素push到列中 minHeightItem.list.push({idx: i, item: this.list[i]}) } return list; },
好了,到这里我能想到的方案就都介绍了。你还有什么方案吗?咱们可以在评论区讨论一下可行性。接下来就是我们的方案总结了。
方案 | 优点 | 缺点 | 点评 |
---|---|---|---|
columns | 实现简单、纯 CSS 方案 | 兼容性 | - |
flex | - | 需要固定高度,填充难以控制等问题 | - |
float、inline、bootstrapGrid | - | - | 没点大都用不出这方案 |
grid | - | - | 可以nth-child模拟实现、或者等待兼容性 masonry |
absolute | 效果好 | - | JS计算无限可能 |
js普通通道 | - | 填充难以控制 | - |
js优化通道 | 效果好、无绝对定位 | 在出现夸列等操作的时候不是很好控制 | - |
更多编程相关知识,请访问:编程入门!!
以上是使用JS或CSS如何實現瀑布流佈局,幾種方案介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!