瀑布流布局视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部
瀑布流的实现方法决定了它的元素排序,具体请看我这篇推文。
纯CSS实现:multi-column多列布局
multi-column使用的是CSS3里的columns属性。兼容性在老版本浏览器上几乎不行。
HTML代码:
<body>
<div class="container">
<div class="item">
<img src="img/bg1.jpg" alt="" />
</div>
<div class="item">
<img src="img/bg2.jpg" alt="" />
</div>
<div class="item">
<img src="img/bg3.jpg" alt="" />
</div>
<div class="item">
<img src="img/bg4.jpeg" alt="" />
</div>
<div class="item">
<img src="img/bg5.jpg" alt="" />
</div>
<div class="item">
<img src="img/bg6.jpg" alt="" />
</div>
<div class="item">
<img src="img/bg7.jpg" alt="" />
</div>
</div>
</body>
此时只需要加上CSS样式即可实现
<style>
.container {
margin: 0 auto;
width: 1000px;
column-count: 3; /* 列数 */
column-gap: 20px; /* 列间距 */
}
.item {
margin-bottom: 10px;
/* 防止多列布局,分页媒体和多区域上下文中的意外中断 */
break-inside: avoid;
}
.item img{
width: 100%;
height:100%;
}
</style>
加上3列的css属性后,元素就会按照从上到下从左到右进行排列了。
缺点:瀑布流的优点动态加载几乎无效(因为它一列一列从上往下)
补充的CSS属性:
- column-gap 元素之间的间隙
- column-width 每一列的宽度
纯Css实现:grid-template-rows属性
CSS 新属性 grid-template-rows: masonry 轻松实现瀑布流布局,一行代码即可搞定。
兼容性?几乎没有。
感兴趣自己去看看,这里不介绍了。
纯CSS实现:flex
- flex 实现瀑布流需要将最外层元素设置为 display: flex
- flex-flow:column wrap 使其纵向排列并且自动换行
- 最外层设置 height: 100vh 填充屏幕的高度,也可以设置为单位为 px 的高度,来容纳子元素
- 每一列的宽度可用 calc 函数来设置,即 width: calc(100%/3 - 20px)。分成等宽的 3 列减掉左右两遍的 margin 距离
<style>
.container {
display: flex;
flex-flow: column wrap;
height: 100vh;
}
.item {
margin: 10px;
width: calc(100%/3 - 20px);
}
.item img{
width: 100%;
height:100%;
}
</style>
但是一拖拽窗口,就会发生变化。为什么呢?我们看代码,每个元素的宽度都被我们固定为三分之一宽度(包括间距)。但是每个元素(可以理解为图片)它们的宽高比并不一样。这也使得每一列能包含的元素数量会随着宽度的改变而改变。
JS实现
思路:将内容宽度一致,高度不一致的图片,从左至右排列,一行内容排满后,下一张就会按顺序排在最短的内容后,以此类推。
<html lang="en">
<body>
<div id="container">
<div class="box">
<div class="box-img">
<img src="./img/bg1.png" alt="">
</div>
</div>
<div class="box">
<div class="box-img">
<img src="./img/bg2.png" alt="">
</div>
</div>
<div class="box">
<div class="box-img">
<img src="./img/bg3.png" alt="">
</div>
</div>
<div class="box">
<div class="box-img">
<img src="./img/bg4.png" alt="">
</div>
</div>
<div class="box">
<div class="box-img">
<img src="./img/bg5.png" alt="">
</div>
</div>
<div class="box">
<div class="box-img">
<img src="./img/bg6.png" alt="">
</div>
</div>
<div class="box">
<div class="box-img">
<img src="./img/bg7.png" alt="">
</div>
</div>
</body>
</html>
CSS样式:
<style>
/*让图片向左浮动*/
.box {
float: left;
}
/*定位*/
.container {
position: relative;
}
.box-img {
width: 150px;
padding: 5px;
}
/*让图片与图片容器宽度相等*/
.box-img img {
width: 100%;
}
</style>
JS部分:
其实很简单,就是先把每一行的元素存到数组去,并找出高度最小的那个元素,储存它的索引,并从第二行开始逐个改变每个元素 的绝对定位的TLBR值。
<script>
window.onload = function () {
imgLocation('container', 'box')
}
//获取到所有要摆放的图片
function imgLocation(parent, content) {
var cparent = document.getElementById(parent)
// cparent 下的所有的第一层的子容器 box
var ccontent = getChildElement(cparent, content) //[装了20个div]
//找从谁开始是需要被摆放位置的
var winWidth = document.documentElement.clientWidth //获取视窗的宽度
var imgWidth = ccontent[0].offsetWidth //获取图片盒子的宽度
var num = Math.floor(winWidth / imgWidth) //向下取整
// 操作第 num+1 张图
var BoxHeightArr = []
for (var i = 0; i < ccontent.length; i++) {
// 前num张只要计算高度
if (i < num) {
BoxHeightArr[i] = ccontent[i].offsetHeight
} else {
//我们要操作的Box
var minHeight = Math.min.apply(null, BoxHeightArr)
var minIndex = BoxHeightArr.indexOf(minHeight)
ccontent[i].style.position = 'absolute'
ccontent[i].style.top = minHeight + 'px'
ccontent[i].style.left = (imgWidth * minIndex) + 'px'
//更新最矮的那一列的高度
BoxHeightArr[minIndex] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
}
}
}
function getChildElement(parent, content) {
var contentArr = []
var allContent = parent.getElementsByTagName('*') //[xxxx数组]
//遍历allContent 把中其类名为 content 的容器都存到contentArr数组中
for (var i = 0; i < allContent.length; i++) {
//当前这个容器的类名是否为 content
if (allContent[i].className == content) {
contentArr.push(allContent[i])
}
}
return contentArr
}
</script>
插件实现
masonry.js
如果在vue项目里想引用的话,可以:
npm install masonry-layout --save
import Masonry from "masonry-layout"; // Vue项目的引入方式
creatd() {
var grid = this.$refs.gridContainer;
var msnry = new Masonry(grid, {
// options...
itemSelector: ".grid-item",
columnWidth: 300,
});
}
我的推荐
使用vue-grid-layout网格布局插件,它也能给你一个瀑布布局