什么是瀑布流布局
瀑布流又称瀑布流式布局,是一种比较流行的页面布局方式,专业的英文名称为[Masonry Layouts]。与传统的分页显示不同,视觉表现为参差不齐的多栏布局,最早是由Pinterest首先运用。
瀑布流布局的优点瀑布流布局的缺点瀑布流布局适用场景瀑布流布局前端技术方案
先说结论,实际工程中推荐直接使用第三方库。
1. css1.1 multi-column 多栏布局
multi-column实现瀑布流主要依赖以下几个属性:
column-count和column-width都可以用来定义分栏的数目,而且并没有明确的优先级之分。优先级的计算取决与具体的场景。
计算方式为:计算column-count和column-width转换后具体的列数,哪个小就用哪个。
.masonry{
column-count: 3;
column-gap: 10px;
}
.masonry .item{
border:1px solid #999;
margin-bottom: 10px;
}
.masonry .item img{
width: 100%;
}
我们可以看到,虽然实现了瀑布流的效果,但奇怪的是例子中前两列的最后一个元素的文本内容被自动断开,一部分在当前列尾,一部分在下一列的列头。
而这种展示方式无疑是我们不希望看到的,我们希望的是每个元素都是独立的,前后不断开,此时我们需要使用break-inside来实现。
break-inside: auto | avoid
修改一下之前的例子:
.masonry .item{
break-inside: avoid;
}
但由于multi-column布局中子元素的排列顺序是先从上往下再从左至右,所以这种方式仅适用于数据固定不变的情况,对于滚动加载更多等可动态添加数据的情况就并不适用了。
1.2 grid 布局实现瀑布流
网格布局(Grid)是最强大的 CSS 布局方案。
它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局。以前,只能通过复杂的 CSS 框架达到的效果,现在浏览器内置了。
关于grid语法可以参照阮一峰的博客CSS Grid 网格布局教程。
.wrap-waterfall--grid img{vertical-align: top;width: 100px}
.wrap-waterfall--grid .list{
display: grid;
grid-gap: 10px;
/* 可以看到,网格大小,占据位置是需要提前设定的 */
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: minmax(50px, auto);
}
网传有 gird 实现瀑布流布局的方案,但是我看了几个他们不是色块,就是图片变形、裁剪,方案是用 nth-child 定高,所以这个方案有局限性,只适用于固定布局,如下图布局,
,显然不满足瀑布流大部分的使用场景。
1.3 Flexbox 实现瀑布流
关于flex语法可以参照阮一峰的博客Flex 布局教程:语法篇。
flex布局默认情况下是水平排列,可以修改为垂直排列并且允许换行达到纵向瀑布流的效果。
flex-flow: column wrap;
height: 2300px;
局限性:必须用固定高度使内容换行,填充比较难以控制;不固定高度的话要结合js才能实现,如下:
<template>
<div class="masonry">
<div class="colmun">
<img class="item" :src="i.img" :key="i.id" v-for="i in data1">
</div>
<div class="colmun">
<img class="item" :src="i.img" :key="i.id" v-for="i in data2">
</div>
<div class="colmun">
<img class="item" :src="i.img" :key="i.id" v-for="i in data3">
</div>
</div>
</template>
<script>
import data from "./data.json";
export default {
data() {
let data1 = [], //第一列
data2 = [], //第二列
data3 = [], //第三列
i = 0;
while (i < data.length) {
data1.push(data[i++]);
if (i < data.length) {
data2.push(data[i++]);
}
if (i < data.length) {
data3.push(data[i++]);
}
}
return {
//第一列
data1,
//第二列
data2,
//第三列
data3
};
}
};
</script>
<style lang="scss" scoped>
.masonry {
display: flex;
flex-direction: row;
.colmun {
display: flex;
flex-direction: column;
flex: 1;
padding: 0 2px;
.item {
margin-bottom: 5px;
width: 100%;
}
}
}
</style>
1.4 grid-template-rows: masonry
看了以上的各种css方案,都有各自的弊端,实际使用场景一般也不会通过纯css做瀑布流布局。
CSS 新属性 grid-template-rows: masonry 轻松实现瀑布流布局,一行代码即可搞定(目前在 FirefoxNightly 可用),看了caniuse,兼容性感人。
后续如果所有浏览器都支持的话,今天写的这篇文章就可以归档了。
2. 原生js
自己实现个瀑布流布局相对比较繁琐,网上的各种js解决方案写法各式各样,不过思路都类似,下面提供一种解决方案供参考:
确定每行放几张图片, 每行的个数(column)=页面宽度(pageWidth)/(图片盒子宽度+图片间距)
确定一行多少个之后首先需要将第一行排列好 (绝对定位的方式,使用js排列好)
找出每一行的最小高度,排列完每一张图片之后更新最小高度
3.第三方库
第三方库才是前端攻城狮智慧的结晶,实际工程中我使用了比较小众的@egjs/vue-infinitegrid,这是egjs-infinitegrid的使用文档,有各类框架的具体使用姿势,涵盖了各种使用场景。
网上还有各类第三方库,比如 vue-waterfall,感兴趣的可以自行尝试。
总结
纯css实现有各自的弊端,兼容性问题不少;
js实现需要评估时间成本,并且可能有未知bug;
实际工程中使用第三方库才是最稳妥的解决方案。