瀑布流源于国外的一家图片分享网站Pinterest,该网站是通过看上去多列布局的方式展示图片,并且每一列高度有内容多少来决定形成列中的项高度不统一形成的层次不齐的砌墙效果。
瀑布流布局实现的多种方法
瀑布流布局看上去属于多列布局的一种,每列宽度相等但是高度不固定,从而形成的类似于砌墙效果。
基础布局介绍
多列瀑布流布局
通过创建相同宽度的多个列然后通过计算哪一列最低然后给列中添加元素来实现。
代码:
<div class="falls-1" id="falls_1">
<div class="columns"></div>
<div class="columns"></div>
<div class="columns"></div>
<div class="columns"></div>
</div>
/* 这里我们通过inline-block来布局 */
.falls-1 {
letter-spacing: -.35em;
}
/* 设置4列,每列占25%宽度 */
.falls-1 .columns {
letter-spacing: normal;
width: 25%;
display: inline-block;
vertical-align: top;
}
.falls-1 .columns div{
background-color: orange;
margin: 0 10px 10px;
padding: 10px;
font-size: 40px;
color:white;
}
var listArray = [];
// 这里我们随机生成100个高度在50-400之间的数据
for (var i = 0; i < 100; i++) {
listArray.push(parseInt(Math.random() * (400 - 50 + 1) + 50, 10));
}
var falls_1 = document.getElementById('falls_1');
var columns = falls_1.children;
// 循环数据数组
for(var x = 0; x<listArray.length; x++){
var curColumns = columns[0];
var item = document.createElement('div');
item.style.height = listArray[x] + 'px';
item.innerText = x;
// 通过判断哪一列最低然后获取最低的列
for(var y = 1; y<columns.length; y++){
if(curColumns.clientHeight>columns[y].clientHeight){
curColumns = columns[y];
}
}
// 把元素添加的最低的列
curColumns.appendChild(item);
}
示例:https://codepen.io/qwguo88/full/WNrEyzZ
相对定位和绝对定位结合实现
通过元素的绝对定位来实现瀑布流相对来说比多列布局要复杂以下,因为他没有列得概念所以需要记录比较低的那一项然后按照这一项来设置要添加的新项的位置,具体代码如下:
代码:
<div class="falls-2" id="falls_2"></div>
/* 这里我们通过inline-block来布局 */
.falls-2 {
position: relative;
}
/* 这里我们给元素设置宽度为25%,也就是按照四列来设置 */
.falls-2 .item{
width: 25%;
position: absolute;
}
/* 为了计算方便我们把所有的间距都在内部的元素中设置,
这样一来我们就不用再计算定位的时候在去额外计算内外间距的距离了 */
.falls-2 .item-inner{
position: absolute;
background-color: orange;
top: 0;
bottom: 10px;
right: 10px;
left: 10px;
padding: 10px;
font-size: 40px;
color:white;
}
// 随机生成100条数据
var listArray = [];
for (var i = 0; i < 100; i++) {
listArray.push(parseInt(Math.random() * (400 - 80 + 1) + 80, 10));
}
// 这里表示列数
var colLength = 4;
var falls_1 = document.getElementById('falls_2');
var colArray = [];
// 通过父级的宽度和设置的列数来计算出每一项的宽度
var itemW = falls_1.clientWidth/colLength;
// 循环列数,初始化第一次元素的初始位置
for(var x = 0; x<colLength;x++){
colArray.push({t: 0, l: x*itemW});
}
// 循环数据
for(var x = 0; x<listArray.length; x++){
// 取第一个初始化数据
var curPosition = colArray[0];
// 然后通过循环判断哪一个数据最低
for(var y = 1; y<colArray.length; y++){
if(curPosition.t > colArray[y].t){
curPosition = colArray[y];
}
}
// 创建元素,并且给元素设置位置信息和宽高等信息
var item = document.createElement('div');
var itemInner = document.createElement('div');
item.setAttribute('class','item');
itemInner.setAttribute('class','item-inner');
item.style.height = listArray[x] + 'px';
item.style.top = curPosition.t + 'px';
item.style.left = curPosition.l + 'px';
item.style.width = itemW + 'px';
itemInner.innerText = x;
item.appendChild(itemInner);
falls_1.appendChild(item);
// 然后更新初始化中的数据,使下次循环时记录
curPosition.t = curPosition.t + listArray[x];
}
示例:https://codepen.io/qwguo88/full/KKVvBWb
纯css实现瀑布流布局–columns
上边的两种方式都是css结合js来实现的,我们也可使只使用css就能实现瀑布流布局,
columns
是css中用来实现多列布局的属性,它可以把元素中的内容以相同宽度分成多列来呈现,我们可以通过此特性来实现瀑布流效果。
<div class="falls-3" id="falls_3">
<div class="item"></div>
<div class="item"></div>
<!-- 这里省略重复多个 -->
...
</div>
.falls-3{
column-count: 4;
column-width: 25%;
column-span: 10px;
padding-top: 10px;
}
.item{
background-color: orange;
margin: 0 0 10px;
padding: 10px;
font-size: 40px;
color:white;
break-inside: avoid;
border-radius: 10px;
}
示例:https://codepen.io/qwguo88/full/oNbGNXj
我们看到上边的代码发现,column实现瀑布流布局非常简单,几行简单的代码就实现了瀑布流布局效果,但是查看输出结果发现这种布局是一列一列的渲染,它是浏览器内部先通过项目的总是计算出每一列放多少内容,然后在一列一列的填充,然后通过项目的break-inside:avoid来实现内部的行不在项的中间断列,这种结果并不是我们在开发中真正想要的效果
实际开发中的应用
在上边的案例中我们只是介绍的在列数固定的情况下并且项目元素为固定高度的情况下实现步骤,但是我们在真正的开发中往往要比这个结构复杂,比如有图片需要等待图片加载完毕后再计算高度,有文字并且文字内容不固定。和现在流行的框架vue,微信小程序等都是通过数据渲染的。接下来我们将介绍各种的实现方法。
带图片的瀑布流
示例:https://codepen.io/qwguo88/pen/ZEQvzLL