欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

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

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

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

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

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

          瀑布流布局是什么?

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

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

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

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

          grid、inline、float 魔性方案

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

          方案 grid inline float bootstrap-grid
          截圖 使用JS或CSS如何實現(xiàn)瀑布流布局,幾種方案介紹 使用JS或CSS如何實現(xiàn)瀑布流布局,幾種方案介紹 使用JS或CSS如何實現(xiàn)瀑布流布局,幾種方案介紹 使用JS或CSS如何實現(xiàn)瀑布流布局,幾種方案介紹

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

          DOM 結(jié)構(gòu)

          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;     /* 可以看到,網(wǎng)格大小,占據(jù)位置是需要提前設定的 */     grid-template-columns: repeat(4, 1fr);     grid-auto-rows: minmax(50px, auto); }

          grid 在某些情況下會比 flex 好用。比如說需要突破行的限制,但是只適用于固定布局,如下圖的布局,如果不使用grid你會如何實現(xiàn)呢?

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

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

          columns、flex CSS實現(xiàn) 不靠譜方案

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

          • 順序是先垂直,后水平
          • (columns)兼容性問題
          • (flex)需要給一個固定高度,會出現(xiàn)超出設定列,以及無法充滿設定列。
          方案 columns flex
          截圖 使用JS或CSS如何實現(xiàn)瀑布流布局,幾種方案介紹 使用JS或CSS如何實現(xiàn)瀑布流布局,幾種方案介紹

          columns 方案

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

          flex 方案

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

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

          方案 absolute 取余分通道 計算高度分通道
          頭部截圖 使用JS或CSS如何實現(xiàn)瀑布流布局,幾種方案介紹 使用JS或CSS如何實現(xiàn)瀑布流布局,幾種方案介紹 使用JS或CSS如何實現(xiàn)瀑布流布局,幾種方案介紹

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

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

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

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

          • 無高度,那么可以通過onload來監(jiān)聽圖片加載完成。等圖片加載完成再去獲取高度。

          • 有高度,這種方案一般用在封面圖、或者文章中,在上傳圖片的時候會保存原圖尺寸,這個時候我們就可以直接使用已有數(shù)據(jù)。

          獲取圖片高度

          // 用于獲取圖片的真實高度 naturalHeight: 1180 // 用于獲取圖片的真實寬度 naturalWidth: 1200  //用戶獲取圖片當前的渲染高度(會受 css 影響) height: 98 //用戶獲取圖片當前的渲染寬度(會受 css 影響) width: 100  // 可返回瀏覽器是否已完成對圖像的加載。如果加載完成,則返回 true,否則返回 fasle。 complete 屬性 // 可以監(jiān)聽到圖片加載完成的動作 onload

          基于上面的內(nèi)容,那我們可以先判斷 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 計算高度方案

          因為普通的布局已經(jīng)無法滿足我們的需求,所以我們可以考慮通過 position: absolute 來使內(nèi)容通過絕對定位來顯示

          核心操作就是維護每個元素的 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 },

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

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

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

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

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

          通過高度計算,然后分通道,避免 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; },

          總結(jié)

          好了,到這里我能想到的方案就都介紹了。你還有什么方案嗎?咱們可以在評論區(qū)討論一下可行性。接下來就是我們的方案總結(jié)了。

          方案 優(yōu)點 缺點 點評
          columns 實現(xiàn)簡單、純 CSS 方案 兼容性
          flex 需要固定高度,填充難以控制等問題
          float、inline、bootstrapGrid 沒點大都用不出這方案
          grid 可以nth-child模擬實現(xiàn)、或者等待兼容性 masonry
          absolute 效果好 JS計算無限可能
          js普通通道 填充難以控制
          js優(yōu)化通道 效果好、無絕對定位 在出現(xiàn)夸列等操作的時候不是很好控制

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號