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

来源:https://www.cnblogs.com/lamian77/archive/2019/09/27/11596698.html
-Advertisement-
Play Games

瀑布流 又稱瀑布流式佈局,是比較流行的一種網站頁面佈局方式。即多行等寬元素排列,後面的元素依次添加到其後,等寬不等高,根據圖片原比例縮放直至寬度達到我們的要求,依次按照規則放入指定位置。 為什麼使用瀑布流 瀑布流佈局在我們現在的前端頁面中經常會用的到,它可以有效的降低頁面的複雜度,節省很多的空間,對 ...


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

 

為什麼使用瀑布流

瀑布流佈局在我們現在的前端頁面中經常會用的到,它可以有效的降低頁面的複雜度,節省很多的空間,對於整個頁面不需要太多的操作,只需要下拉就可以瀏覽用戶需要看到的數據;並且,在當前這個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 的區別

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>簡易計算器</title> <script src="./lib/vue.js"></script> </head> <body> <div id="app">... ...
  • 1.安裝 less 和 less-loader。 命令: npm install less less-loader --save-dev 2.打開 build/webpack.base.conf.js ,在 module.exports = 的對象的 module.rules 後面 添加一段:{te ...
  • 在面試題中,閉包應該是必問的問題吧(以下內容純屬個人理解,歡迎大家指正不足) 下麵我們就簡單的瞭解一下閉包這個東西到底是什麼 首先,我們先來講講什麼是閉包 簡單來說就是一個定義在函數內部的函數,可以讀取到其他函數內部變數的函數,本質上,閉包就是一個把函數內部和外部連接起來的橋梁 那我們讀取函數內部的 ...
  • Hexo 是一個輕量級、簡潔、高效且高逼格的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在幾秒內,即可利用靚麗的主題生成靜態網頁。同時有著豐富的主題,官網或者GitHub都可以輕鬆下載到。由於Hexo博客都是靜態文件,所以推薦部署在Github上,不需要額外的伺服器和後臺, ...
  • 要知道這幾種寫法之間的區別,我們要先聊些題外話——js中函數的兩種命名方式,即表達式和聲明式。 函數的聲明式寫法為:function foo(){/*...*/},這種寫法會導致函數提升,所有function關鍵字都會被解釋器優先編譯,不管是聲明在什麼位置,都可以調用它,但是它本身不會被執行,定義只 ...
  • nodejs項目周 nodejs前端框架 一般做中間層 和操作資料庫 傳統模式和前後端分離最大的區別就是seo優化 HTTP常見的伺服器軟體 Apache Nginx (iis)微軟的伺服器現在已經不怎麼用了 node伺服器 可以自己編寫服務 個人練習 nodejs依賴安裝 Express框架 提供 ...
  • 版權申明: 本文原創首發於以下網站,您可以自由轉載,但必須加入完整的版權聲明 博客園MogooStudio: csdn博客MogooStudio: 最後效果 源碼分享 以下步驟詳細內容可能跟源碼中有出入,一切以源碼為準 CocosCreator版本:2.1.2,務必使用大於此版本的引擎運行 源碼地址 ...
  • 在練習jQuery表格變色例子過程中,發現了一下幾個問題: 針對以上問題,查閱了資料後,發現了原因,以及解決方法: 在之前的jQuery版本中,都是使用attr()訪問對象的屬性,比如取一個圖片的alt屬性,就可以這樣做$('#img').attr('alt');但是在某些時候,比如訪問input的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...