日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

本篇文章帶大家了解一下瀑布流布局,介紹一下三種靠譜JS方案,以及N種不靠譜CSS方案。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。


使用JS或CSS如何實現瀑布流布局,幾種方案介紹


本著實用精神,我們今天來分享一下瀑布流布局(昨天有個小兄弟問我怎么做,我找了半天沒找到,啊原來寫在內網了)。


瀑布流布局是什么?

比如說 花瓣網、蘑菇街 (我下面貼圖了), 這些網站在顯示內容的時候就使用了瀑布流布局。

我們也想做一個展示我們設計稿(定寬,不定高)的頁面,瀑布流是很棒的一種方案。

瀑布流布局其核心是基于一個網格的布局,而且每行包含的項目列表高度是隨機的(隨著自己內容動態變化高度),同時每個項目列表呈堆棧形式排列,最為關鍵的是,堆棧之間彼此之間沒有多余的間距差存大。還是上圖來看看我們說的瀑布流布局是什么樣子。


使用JS或CSS如何實現瀑布流布局,幾種方案介紹


grid、inline、float 魔性方案

也算是純 CSS 方案吧,本質上來講是依賴文檔流,從左到右,從上到下。


使用JS或CSS如何實現瀑布流布局,幾種方案介紹


可以看到在文檔流布局中有非常明顯的的概念,當一個行被撐開就會留下空白,行與行不會重疊。這里最魔性的就是 float 布局了。


DOM 結構

div.list     // 設置 gird 或者 block,注意清除浮動
  div.item   // 設置為 inline 或者 float,使其能流動
    img      // 設置定寬,高度自適應,間距等。


grid 方案說明

.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你會如何實現呢?


使用JS或CSS如何實現瀑布流布局,幾種方案介紹


網傳有 gird 實現瀑布流布局的方案,但是我看了幾個他們不是色塊,就是圖片變形、裁剪,方案是用 nth-child 定高,太恐怖了吧。


columns、flex CSS實現 不靠譜方案

也是純 CSS 方案,相比較上面的方案而言,方案已經可以接受,只是還有部分問題。

順序是先垂直,后水平

(columns)兼容性問題

(flex)需要給一個固定高度,會出現超出設定列,以及無法充滿設定列。


使用JS或CSS如何實現瀑布流布局,幾種方案介紹


columns 方案

天生支持,只需要給父級設置即可 columns: 4; column-gap: 6px; 。


flex 方案

flex-flow: column wrap;height: 2300px; 默認情況下是水平排列,通過修改為垂直排列并且允許換行,之后把通過固定高度使內容換行。

absolute、通道 高度計算方案 靠譜方案


使用JS或CSS如何實現瀑布流布局,幾種方案介紹


這里的方案就靠譜起來了,可以滿足我們使用要求。

我們來回憶一下我們的需求:展示一些內容,內容有特性定寬,不定高。不定高一般是因為內容長度或者高度不一致導致的,常見內容又分為兩種文字和圖片。

文字的話,在沒有異步字體的情況下,可以理解為同步就可以獲取到盒子高度。

圖片的話,因為加載是異步的,所以獲取盒子的真實高度也是異步的。但是這里一般分為兩種情況

無高度,那么可以通過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)
*/

absolute 計算高度方案

因為普通的布局已經無法滿足我們的需求,所以我們可以考慮通過 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
},

通過計算,我們可以到,瀑布流布局下每個元素的位置,通過絕對定位就可以實現。

根據下標,來渲染到不同的通道 idx % 4

因為上個方案用到了絕對定位,那么有沒有不用絕對定位的方案呢?回到我們的問題點上 定寬,不定高,那我們完全可以通過分開渲染放棄 absolute 來實現。

jsGroupList(){
    return this.list.reduce((s,n,idx)=>{
        // 根據下標,直接分配所屬列
        s[idx % 4].push({idx: idx, item: n})
        return s
    }, [[],[],[],[],])
},

看開頭是實現類似的功能的,但是有一個弊端(快來評論區回復呀)。

通過高度計算,然后分通道,避免 absolute

因為上一個方案是按下標分類的,其實瀑布流是按高度分類的,所以我們分類條件換成最低的列。

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優化通道效果好、無絕對定位在出現夸列等操作的時候不是很好控制-


分享到:
標簽:瀑布流布局
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定