一、基本思路
1、先看最終的效果圖:

2、實現原理:通過position:absolute(絕對定位)來定位每一個元素的位置,並且將當前列的高度記錄下來方便下一個dom位置的計算
二、代碼實現
1、版本一:根據思路實現基礎版
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>css布局-瀑布流的實現</title>
<style type="text/css">
.box {
position: relative;
width: 500px;
min-height: 100px;
margin: 100px auto;
background: #eeeeee;
}
.item {
position: absolute;
width: 120px;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div class="box">
<div class="item" style="height: 40px;background: red;"></div>
<div class="item" style="height: 50px;background: blue;"></div>
<div class="item" style="height: 100px;background: green;"></div>
<div class="item" style="height: 60px;background: gray;"></div>
<div class="item" style="height: 50px;background: orange;"></div>
<div class="item" style="height: 20px;background: yellow;"></div>
<div class="item" style="height: 40px;background: red;"></div>
<div class="item" style="height: 50px;background: blue;"></div>
<div class="item" style="height: 100px;background: green;"></div>
<div class="item" style="height: 120px;background: gray;"></div>
<div class="item" style="height: 58px;background: orange;"></div>
<div class="item" style="height: 36px;background: yellow;"></div>
</div>
<script type="text/javascript">
const BOX_WIDTH = document.querySelector('.box').offsetWidth //瀑布流外層盒子的寬度
const ITEM_WIDTH = document.querySelector('.item').offsetWidth //瀑布流內層盒子的寬度
const COLUMN = Math.floor(BOX_WIDTH/ITEM_WIDTH) //根據寬度計算可渲染的列數
const MARGIN = (BOX_WIDTH - ITEM_WIDTH*COLUMN)/(COLUMN-1) // 根據寬度計算每一列的間距
const MARGINTOP = 10 //固定設置每一個小盒子上下間距是10
let height_arr = new Array(COLUMN).fill(0) //定義一個長度等同與列數的數組用來存儲每一列的高度,初始值均為0
let item = document.querySelectorAll('.item')
//遍歷每一個小盒子,確定小盒子的位置
for(let i = 0; i < item.length; i++) {
let index = height_arr.indexOf(Math.min.apply(null, height_arr))
item[i].style.left = (ITEM_WIDTH + MARGIN) * index + 'px'
item[i].style.top = height_arr[index] + MARGINTOP + 'px'
height_arr[index] += item[i].offsetHeight + MARGINTOP
}
//將數組中最大的值,即最高的那一列的高度賦給外層盒子
document.querySelector('.box').style.height = Math.max.apply(null, height_arr) + 'px'
</script>
</body>
</html>
2、版本二:對版本一進行封裝,方便重復使用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>css布局-瀑布流的實現</title>
<style type="text/css">
.box {
position: relative;
width: 500px;
min-height: 100px;
margin: 100px auto;
background: #eeeeee;
}
.item {
position: absolute;
width: 120px;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div class="box" style="">
<div class="item" style="height: 40px;background: red;"></div>
<div class="item" style="height: 50px;background: blue;"></div>
<div class="item" style="height: 100px;background: green;"></div>
<div class="item" style="height: 60px;background: gray;"></div>
<div class="item" style="height: 50px;background: orange;"></div>
<div class="item" style="height: 20px;background: yellow;"></div>
<div class="item" style="height: 40px;background: red;"></div>
<div class="item" style="height: 50px;background: blue;"></div>
<div class="item" style="height: 100px;background: green;"></div>
<div class="item" style="height: 120px;background: gray;"></div>
<div class="item" style="height: 58px;background: orange;"></div>
<div class="item" style="height: 36px;background: yellow;"></div>
</div>
<script type="text/javascript">
function WaterFall(params) {
this.box = (params && params.parent) || '.box'
this.item = (params && params.child) || '.item'
this.column = (params && params.column) || 0
this.row_margin = (params && params.row_margin) || 0
this.column_margin = (params && params.column_margin) || 10
this.height_arr = []
this._box_width = 0
this._item_width = 0
this._computed = function() {
this._box_width = document.querySelector(this.box).offsetWidth
this._item_width = document.querySelector(this.item).offsetWidth
this.column = Math.floor((this._box_width - this.row_margin)/this._item_width) //列數
this.row_margin = !this.row_margin ? (this._box_width - this._item_width * this.column)/(this.column-1) : this.row_margin
}
this.init = function() {
this._computed()
let item = document.querySelectorAll(this.item)
this.height_arr = new Array(this.column).fill(0)
for(let i = 0; i < item.length; i++) {
let index = this.height_arr.indexOf(Math.min.apply(null, this.height_arr))
item[i].style.left = (this._item_width + this.row_margin) * index + 'px'
item[i].style.top = this.height_arr[index] + this.column_margin + 'px'
this.height_arr[index] += item[i].offsetHeight + this.column_margin
}
document.querySelector('.box').style.height = Math.max.apply(null, this.height_arr) + 'px'
}
}
var test = new WaterFall()
test.init()
</script>
</body>
</html>
三、總結:瀑布流的實現並不復雜,只要清楚了原理剩下的就是耐心的計算間距以及小盒子的位置啦~
