@
前言
瀑布流 網站頁面佈局
瀑布流,又稱瀑布流式佈局。是比較流行的一種網站頁面佈局,視覺表現爲參差不齊的多欄佈局,隨着頁面滾動條向下滾動,這種佈局還會不斷加載數據塊並附加至當前尾部。最早採用此佈局的網站是Pinterest,逐漸在國內流行開來。國內大多數清新站基本爲這類風格。
簡單來說: 瀑布流式佈局其實式一種網頁的樣式效果,簡單來說就是一種單個寬度固定,單個圖片高度根據內容適應,多個塊自動換行,但是緊湊拼在一起的效果。既可以使用純css快速的達到這種樣式效果,也可以通過JavaScript輔助,實現更豐富合理的效果
一、使用css實現瀑布流佈局
1.flex
佈局
使用flex佈局,將容器設置爲flex佈局,設置主軸方向爲列方向,允許換行,容器設定固定高度(這樣纔會自動換列),然後子元素設置寬度爲對應比例,在某一列填滿時會自動往下一列填充,並且每一列元素填充十分緊湊****
優化方向:使用order屬性優化排序方向
2.column-count
多欄佈局
類似的還有使用 多欄佈局,使用column-count
屬性,設置多欄佈局,效果跟flex佈局類似,排列方向也是從上到下,從左到右
3.grid
網格佈局
二、結合JavaScript的瀑布流佈局實現
1.推薦原因
瀑布流式佈局經常被使用在圖片的展示頁面,大量的圖片資源加載,如果只用css樣式的話必須一次性加載所有圖片,我們期待的是瀑布流和懶加載結合在一起,在滾動視圖的同時,不斷加載下面的內容
2.實現步驟
如果需要結果的話可以直接跳到文章最後
a.初步實現:結合JavaScript實現瀑布流
原理:
- 子元素
絕對定位
- 通過
javascript
設置偏移量
html代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div id="app"></div>
<!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script> -->
<!-- <script src="./src/vue.min.js"></script> -->
<script src="./util.js"></script>
<script src="./index.js"></script>
</body>
</html>
css 代碼:
html {
background-color: black;
}
#app {
position: relative;
width: 100%;
margin: auto;
}
.item {
position: absolute;
border-radius: 20px;
border: 10px solid black;
box-sizing: border-box;
text-align: center;
color: white;
}
utils.js 代碼:
const randomImgSize = [ // 這裏是模擬各種尺寸的圖片
{
width:1920,
height:1080
},{
width:640,
height:720
},{
width:720,
height:680
},{
width:720,
height:1920
},{
width:900,
height:600
},{
width:400,
height:300
},{
width:2048,
height:1920
},{
width:700,
height:900
},{
width:1600,
height:900
},{
width:200,
height:200
}
]
function randomColor(){
let r = Math.floor(Math.random() * 255)
let g = Math.floor(Math.random() * 255)
let b = Math.floor(Math.random() * 255)
return `rgb(${r},${g},${b})`
}
index.js 代碼
// 創建元素函數
function generateBlock(size,color){
let dom = document.createElement('div')
dom.setAttribute('class','item')
dom.style.width = '240px' // 這裏默認寫死寬度,後面會優化
dom.style.height = `${240/size.width * size.height}px` // 由於這裏沒有圖片資源,高度模擬計算
// 圖片資源的話不需要直接width:100% 高度會自適應
dom.style.backgroundColor = color
// 顏色也是隨機生成而已
document.getElementById('app').appendChild(dom)
return dom
}
// 元素統計數組
let domArr = []
// 元素高度數組
let heightArr = new Array(4) // 創建對應列數,存儲每一列高度,用來設置偏移量
heightArr.fill(0)
// 常規不考慮高度不整齊邏輯
randomImgSize.forEach(ele=>{
let dom =generateBlock(ele,randomColor())
domArr.push(dom) // 通過transform 屬性可以一次設置,不用設置left和top,不過也一樣
dom.style.transform = `translate(${(domArr.length-1)%4 * 100}%, ${heightArr[domArr.length%4]}px)`
heightArr[domArr.length%4] += dom.offsetHeight
})
實現內容:
-
初步實現瀑布流佈局,正確計算每一個塊(圖片)的正確位置
-
每個塊只是死板的按照從左到右,從上到下的順序,可以優化:下一個塊生成位置爲當前列最低高度位置,自動填補進去
-
沒有實現懶加載
b.稍微優化:每次自動填補到高度最低
index.js
// 創建元素函數
function generateBlock(size,color){
let dom = document.createElement('div')
dom.setAttribute('class','item')
dom.style.width = '240px'
dom.style.height = `${240/size.width * size.height}px`
dom.style.backgroundColor = color
document.getElementById('app').appendChild(dom)
return dom
}
// 元素統計數組
// let domArr = []
// 元素高度數組
let heightArr = new Array(4)
heightArr.fill(0)
// 常規不考慮高度不整齊邏輯
// randomImgSize.forEach(ele=>{
// let dom =generateBlock(ele,randomColor())
// domArr.push(dom)
// dom.style.transform = `translate(${(domArr.length-1)%4 * 100}%, ${heightArr[domArr.length%4]}px)`
// heightArr[domArr.length%4] += dom.offsetHeight
// })
// 考慮高度不整齊邏輯
randomImgSize.forEach(ele=>{
let dom =generateBlock(ele,randomColor())
let minHeight= Math.min(...heightArr)
let minHeightIndex = heightArr.indexOf(minHeight)
dom.style.transform = `translate(${minHeightIndex * 100}%, ${minHeight}px)`
heightArr[minHeightIndex] += dom.offsetHeight
})
實現效果:
- 可以看到效果對比之前還是要好很多,不會出現極高或者極低的情況,而且代碼還簡化了,不需要數組來緩存元素,直接通過長度爲4 的高度數組,查詢應該插入到哪個列
- 對應列的偏移量:
x
爲 100% * 對應列下標,y
爲對應列下標高度 - 但是寬度還是寫死的,而且沒有實現懶加載
b.最終結果 (不到三十行代碼)支持懶加載
index.js
// 響應式
const columns = 3
let tempArr = new Array(columns) // 創建數組用來緩存高度
tempArr.fill(0)
function create(){
let observer = new IntersectionObserver(callback)
function callback(entries){
if(entries[0].isIntersecting){ // 如果已進入視圖,停止監聽,並且生成新的元素
observer.unobserve(dom)
create()
}
}
function generateBlock(size,color){
let dom = document.createElement('div')
dom.setAttribute('class','item')
dom.style.width = `${Math.floor(100/columns)}%` // 寬度爲百分比
dom.style.height = `${300/size.width * size.height}px` // 300爲默認高度
dom.style.backgroundColor = color
document.getElementById('app').appendChild(dom)
return dom
}
let donSizeIndex = Math.floor(Math.random() * randomImgSize.length) // 隨機生成大小(模擬不同尺寸的圖片)
let dom =generateBlock(randomImgSize[donSizeIndex],randomColor()) // 生成隨機塊
let minHeight= Math.min(...tempArr) // 找到對應列最小高度的值
let minHeightIndex = tempArr.indexOf(minHeight) // 找到對應列最小高度的下標
dom.style.transform = `translate(${minHeightIndex*100}%, ${minHeight}px)` // 根據下標進行變換,變換寬度爲偏移多少個下標,上下爲該下標所有高度
tempArr[minHeightIndex] += dom.offsetHeight // 對應下標增加高度
observer.observe(dom) // 觀察該元素用作懶加載
}
create()
實現效果:
實現比較簡單其實,主要是javascript
操作樣式,設置對應transform
屬性,通過全局設置一個高度數組,每次添加元素時獲取每一列高度,選取最小高度列,將元素偏移量
設置正常,並且通過intersectionObserver
對象,監聽與視口交叉事件
,每次觸發時,生成新的元素
同理可以拓展到加載圖片..等等
總結
以上就是今天要的結合JavaScript實現圖片瀑布流式佈局+懶加載的實現過程,本文僅僅簡單介紹了瀑布流佈局相關設計思路,如果需要增加其他功能可以在該demo的基礎上進行修改
覺得有幫助的話,點贊關注支持一下,b站前端同名分享號:猿油站