關於瀑布流的布局原理分析(純CSS瀑布流與JS瀑布流)


瀑布流 又稱瀑布流式布局,是比較流行的一種網站頁面布局方式。即多行等寬元素排列,后面的元素依次添加到其后,等寬不等高,根據圖片原比例縮放直至寬度達到我們的要求,依次按照規則放入指定位置。

 

為什么使用瀑布流

瀑布流布局在我們現在的前端頁面中經常會用的到,它可以有效的降低頁面的復雜度,節省很多的空間,對於整個頁面不需要太多的操作,只需要下拉就可以瀏覽用戶需要看到的數據;並且,在當前這個APP至上的時代,瀑布流可以提供很好的用戶體驗,通過結合下拉刷新,上拉加載進行數據的懶加載等操作,對於用戶的體驗感來說是接近於滿分的!

 

瀑布流的特點

其實瀑布流的特點就是參差不齊的排列方式,以及流式布局的擴展性,可以通過界面展示給用戶多條數據,並且讓用戶可以有向下瀏覽的沖動。

 

瀑布流的代碼實現

1.純 css 瀑布流:( multi-columns 方法 )

// 這里是第一次接觸到 column-columns 這個屬性,這是一個可以設置將div元素中的文本分成幾列

//默認值是:auto

//寫法:

column-count:3;

-moz-column-count:3; /* Firefox */

-webkit-column-count:3; /* Safari and Chrome */

/* 注意:IE9及更早 IE 版本瀏覽器不支持 column-count 屬性 */

//這里還會用到另一個屬性 column-gap,用來調整邊距,實現瀑布流布局

 

html結構代碼如下:

 1 <div class="demo-1"> 
 2     <div class="item"> 
 3         <div class="item_content content-lar" style="height:100px;" > 1</div> 
 4     </div> 
 5     <div class="item"> 
 6         <div class="item_content content-sma"style="height:150px;" > 2</div> 
 7     </div>
 8     <div class="item"> 
 9         <div class="item_content content-mid"style="height:50px;" > 3</div> 
10     </div>
11     <div class="item"> 
12         <div class="item_content content-sma" style="height:200px;" > 4</div> 
13     </div>
14     <div class="item"> 
15         <div class="item_content content-mid"style="height:60px;" > 5 </div> 
16     </div>
17     <div class="item"> 
18         <div class="item_content content-lar"style="height:90px;" > 6</div> 
19     </div> 
20     <div class="item"> 
21         <div class="item_content content-sma"> 7</div> 
22     </div>
23     <div class="item"> 
24         <div class="item_content content-lar"style="height:120px;" > 8</div> 
25     </div>
26     <div class="item"> 
27         <div class="item_content content-lar"> 9</div> 
28     </div>
29     <div class="item"> 
30         <div class="item_content content-sma" style="height:100px;" > 10 </div> 
31     </div>
32     <div class="item"> 
33         <div class="item_content content-mid"> 11 </div> 
34     </div>
35     <div class="item"> 
36         <div class="item_content content-mid"style="height:100px;" > 12</div> 
37     </div>
38     <!-- more items --> 
39 </div>

 

CSS代碼如下:

 1 .demo-1{  2  -moz-column-count:3; /* Firefox */  3  -webkit-column-count:3; /* Safari 和 Chrome */  4  column-count:3;  5  -moz-column-gap: 1em;  6  -webkit-column-gap: 1em;  7  column-gap: 1em;  8  width: 80%;  9  margin:0 auto; 10  } 11  .item { 12  padding: 2em; 13  margin-bottom: 2em; 14  -webkit-column-break-inside: avoid; 15  break-inside: avoid; /*防止斷點*/ 16  background: #ccc; 17  text-align: center; 18     }

 

效果圖:

 

這里有個弊端,這並不符合瀑布流的原理,如果使用純css寫瀑布流,則每一塊都是從上往下排列,不能做到從左到右排列,並且不會識別哪一塊圖片放在哪個地方合適,若是再配合動態加載,效果會特別不好,所以只能通過JS來實現瀑布流。

那么這里用圖片來分析一下我們想要的瀑布流是什么樣的。

 

瀑布流的位置分析圖解

如下方圖片。假設一排放5張圖片。當第一排排滿足夠多的等寬圖片時,顯示的是這樣的。那么假如我們要放第6張圖片的時候,應該放在什么位置呢?

如果按照我們的正常邏輯來想,應該是放在第一張圖片下面,依次水平排列過去(如下圖)

但現實並非如此!在瀑布流中,從第2行開始,接下去的每一張圖片都會放在上行中高度最低的那一列圖片下方。(如下圖)

 

為什么呢?因為放置它之前,這一列的高度為所有列中最小,所以會放置在這個地方。

那么如果再繼續放置下去,第七張圖片應該放在第三列圖片下方,以此類推。

 

所以每次加載圖片時,會需要判斷哪一列的圖片累計的高度最小,那么下一張圖片就放在哪一列,即瀑布流算法去判斷圖片的確定位置。

 

JS代碼實現

實現思路:

  1.   設定每一列圖片的寬度和間距
  2.   獲取當前窗口的總寬度,從而根據圖片寬度去旁段分成幾列
  3.   獲取所有圖片元素,定義一個空數組來保存高度
  4.   遍歷所有容器,開始判斷  當頁面加載完成,或頁面寬度發生變化時,調用函數。
    • 如果當前處於第一行時: 直接設置圖片位置【 即 top為間距的大小,left為(當前圖片的寬度+間距) * 當前圖片的值+間距大小 】,並保存當前元素高度。
    • 如果當前不處於第一行時:進行高度對比,通過遍歷循環,拿到最小高度和相對應的索引,設置圖片位置【 即 top為最小高度值+間距*2,left為 (當前圖片的寬度+間距) * 索引 值+間距大小)】,並修改當前索引的高度為當前元素高度。
  5.   當頁面加載完成,或頁面寬度發生變化時,調用函數。

 

代碼實現

 

 1 <script type="text/javascript">
 2     // 定義瀑布流算法函數
 3     function fall() {
 4         const minGap = 20; // 最小間距,讓每一列的最小空隙可以自定義,避免太過擁擠的情況發生。但是,會通過計算得到真實的間距。
 5         const itemWidth = 300; // 每一項的寬度,即當前每一個圖片容器的寬度。保證每一列都是等寬不等高的。
 6         const scrollBarWidth = getScrollbarWidth();    // 獲取滾動條的寬度
 7         const pageWidth = window.innerWidth - scrollBarWidth; // 獲取當前頁面的寬度 = window.innerWidth - 滾動條的寬度
 8         const column = Math.floor(pageWidth / (itemWidth + minGap)); // 實際列數=頁面寬度/(圖片寬度+最小間距)
 9         const gap = (pageWidth - itemWidth * column) / column/2; // 計算真實間距 = (頁面寬度- 圖片寬度*實際列數)/實際列數/2
10         const items = document.querySelectorAll('img'); // 獲取所有的外層元素
11         const heightArr = []; // 定義一個空數組,保存最低高度。
12         
13         // 獲取滾動條的寬度
14         function getScrollbarWidth() {
15             const oDiv = document.createElement('div');//創建一個div
16             // 給div設置樣式。隨便定義寬高,只要能獲取到滾動條就可以
17             oDiv.style.cssText = `width: 50px;height: 50px;overflowY: scroll;` 
18             document.body.appendChild(oDiv);//把div添加到body中
19             const scrollbarWidth = oDiv.offsetWidth - oDiv.clientWidth;// 使最大寬度和可視寬度相減,獲得到滾動條寬度。
20             oDiv.remove();//移除創建的div
21             return scrollbarWidth;//返回滾動條寬度
22         }
23         
24         
25         for (let i = 0; i < items.length; i++) {
26             // 遍歷所有的外層容器
27             const height = items[i].offsetHeight;
28             // 如果當前處在第一行
29             if (i < column) {
30                 // 直接設置元素距離上部的位置和距離左邊的距離。
31                 items[i].style.cssText = `top: ${gap}px;left: ${(itemWidth + gap) * i + gap}px`;
32                 // 保存當前元素的高度。
33                 heightArr.push(height);
34             } else {
35                 // 不是第一行的話,就進行比對。
36                 let minHeight = heightArr[0]; // 先保存第一項的高度
37                 let minIndex = 0; // 保存第一項的索引值
38                 for (let j = 0; j < heightArr.length; j++) {
39                     // 通過循環遍歷比對,拿到最小值和最小值的索引。
40                     if (minHeight > heightArr[j]) {
41                         minHeight = heightArr[j];
42                         minIndex = j;
43                     }
44                 }
45                 // 通過最小值為當前元素設置top值,通過索引為當前元素設置left值。
46                 items[i].style.cssText = `top: ${minHeight + gap *2}px; left: ${(itemWidth + gap) * minIndex + gap}px`;
47                 // 並修改當前索引的高度為當前元素的高度
48                 heightArr[minIndex] = minHeight + gap + height;
49             }
50         }
51     }
52     // 頁面加載完成調用一次。
53     window.onload = fall;
54     // 頁面尺寸發生改變再次調用。
55     window.onresize = fall;
56 </script>

 

 

最終效果圖:

 

總結瀑布流布局原理

  • 設置圖片寬度一致
  • 根據瀏覽器寬度以及每列寬度計算出列表個數,列表默認0
  • 當圖片加載完成,所有圖片依次放置在最小的列數下面
  • 父容器高度取列表數組的最大值

引申知識點

  • let,const以及var三者的區別
  • 滾動加載圖片(懶加載原理)
  • 反撇號(`)基礎知識
  • style和style.cssTest 的區別

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM