站長資訊網
        最全最豐富的資訊網站

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

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

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

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

        演示地址: http://www.lilnong.top/static/html/waterfall.html

        瀑布流布局是什么?

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

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

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

        網站 蘑菇街 花瓣網 京東 VV
        截圖 使用JS或CSS如何實現瀑布流布局,幾種方案介紹 使用JS或CSS如何實現瀑布流布局,幾種方案介紹 使用JS或CSS如何實現瀑布流布局,幾種方案介紹 使用JS或CSS如何實現瀑布流布局,幾種方案介紹
        方案 分通道 absolute

        grid、inline、float 魔性方案

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

        方案 grid inline float bootstrap-grid
        截圖 使用JS或CSS如何實現瀑布流布局,幾種方案介紹 使用JS或CSS如何實現瀑布流布局,幾種方案介紹 使用JS或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)需要給一個固定高度,會出現超出設定列,以及無法充滿設定列。
        方案 columns flex
        截圖 使用JS或CSS如何實現瀑布流布局,幾種方案介紹 使用JS或CSS如何實現瀑布流布局,幾種方案介紹

        columns 方案

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

        flex 方案

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

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

        方案 absolute 取余分通道 計算高度分通道
        頭部截圖 使用JS或CSS如何實現瀑布流布局,幾種方案介紹 使用JS或CSS如何實現瀑布流布局,幾種方案介紹 使用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優化通道 效果好、無絕對定位 在出現夸列等操作的時候不是很好控制

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 日韩三级精品| 国产精品久久久久国产A级| 久久棈精品久久久久久噜噜| 精品欧美小视频在线观看| 国产精品一区二区久久| 四虎国产精品永久在线观看| 精品国产呦系列在线观看免费| 99精品高清视频一区二区| 亚洲AV午夜福利精品一区二区| 国产三级精品三级在线观看| 亚洲精品天天影视综合网| 91精品成人免费国产| 久久国产欧美日韩精品| 亚洲性日韩精品一区二区三区| 国产一区二区三区欧美精品| 精品久久777| 国产短视频精品一区二区三区| 久久精品国产亚洲av高清漫画 | 合区精品中文字幕| 精品成人一区二区三区四区| 国产三级精品三级在专区| 成人精品一区二区久久| 国内精品久久九九国产精品| 国产精品莉莉欧美自在线线| 国产精品va无码一区二区| 国产精品兄妹在线观看麻豆| 国内揄拍高清国内精品对白| 久久精品九九亚洲精品| 国产亚洲精品无码成人| 精品久久久久中文字幕日本| 精品人妻码一区二区三区| 99久久精品午夜一区二区| 国产a∨精品一区二区三区不卡| 国产精品igao视频网网址| 韩国精品欧美一区二区三区| 久久精品国内一区二区三区| 亚洲精品欧美日韩| 国产精品免费αv视频| 精品视频一区二区三区四区五区| 欧洲精品码一区二区三区免费看 | 国内精品久久久久影院网站|