手摸手,带你实现移动端H5瀑布流布局
移动端瀑布流布局是一种比较流行的网页布局方式,视觉上来看就是一种像瀑布一样垂直落下的排版。每张图片并不是显示的正正方方的,而是有的长有的短,呈现出一种不规则的形状。但是它们的宽度通常都是相同的
因为移动端瀑布流布局主要为竖向瀑布流,因此本文所探讨的是竖向瀑布流
特点
竖向瀑布流布局主要有下面几种特点:
- 一般出现在移动端 H5 页面底部
- 主要以图片或视频为主
- 降低页面复杂度,节省空间,可以容纳更多内容
- 不规则展示,不会那么枯燥,用户体验好
- 难以或者说不能滚动到页面最底部
不同于传统的分页,瀑布流因为以上这些特点一般被用在这些场景下:
推荐机制下的信息即根据用户画像推荐或者运营人员推荐的信息大分类下的信息流展示的信息有很多,它们的大分类都是相同的,适合用户不明确详细需要获得什么信息或商品的情况下各个信息或商品之间没有比较强的相关性和上面一条类似,展示的不是千遍一律的东西,相对独立的信息或商品也许能让用户意外发掘到想要的东西
实现
一般来说主要分为 CSS 实现和 JS 实现
CSS 实现主要是用到一些专门的样式属性,实现起来简单,但是往往会有兼容性问题
JS 实现的方法则不存在这些问题,并且能实现比较个性化的需求,但是实现起来比较麻烦
column 多列布局方法
column 实现瀑布流主要依赖两个属性
column-count 属性是设置共有几列
column-gap 属性是设置每列之间的间隔
column 兼容性

代码
<style>
.pic {
column-count: 3;
column-gap: 5px;
}
.pic .item {
border: 1px solid #ccc;
margin-bottom: 5px;
}
.item img {
width: 100%;
}
</style>
<body>
<div class="pic">
<div class="item">
<!-- 获取 api 取到的图片地址 -->
<img src="" />
<div>001</div>
</div>
······
<div class="item">
<img src="" />
<div>008</div>
</div>
</div>
</body>
flex 弹性布局方法
flex 实现瀑布流需要给父元素设置为横向排列。然后通过设置 flex-flow: column wrap 使其换⾏
代码
<style>
.pic {
display: flex;
flex-flow: column wrap;
height: 100vh;
}
.item {
/* 每行展示 3 个 */
width: calc(100%/3 - 5px);
border: 1px solid #ccc;
margin-bottom: 5px;
}
.item img {
width: 100%;
}
</style>
<body>
<div class="pic">
<div class="item">
<!-- 获取 api 取到的图片地址 -->
<img src="" />
<div>001</div>
</div>
······
<div class="item">
<img src="" />
<div>008</div>
</div>
</div>
</body>
效果

可以发现图片排序顺序是先垂直方向,然后才是水平方向的。column 多列布局和 flex 弹性布局方法实现的效果图最终相似
JS + 懒加载方法
在不考虑兼容性或者没有特殊图片展示顺序需求下,只是实现瀑布流的话上面两种方案是够用的。如果要实现一些个性化的需求的话,还是得用 JS
主要思路就是:
- 先将第一行排满
- 计算第一行的所有图片高度,将第二行第一张图放在第一行最矮的图片后面
- 进行玩步骤 2,重新计算当前所有列高度,避免步骤 2 添加完成后,该列高度还是最矮
完整代码
<!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>JS实现瀑布流</title>
<style>
.item {
box-sizing: border-box;
border: 1px solid #ccc;
position: absolute;
/* 展示为三列,减去间隔宽度 */
width: calc(100% / 3 - 5px);
}
.item img {
width: 100%;
}
</style>
</head>
<body>
<div id="pic">
<div class="item">
<img src="..." />
<div>001</div>
</div>
<!-- 剩余图片,实际场景中应该使用for循环 -->
<div class="item">
<img src="..." />
<div>015</div>
</div>
</div>
</body>
<script>
var pic = document.getElementById('pic');
var items = pic.children;
// 相邻间距为5像素
var space = 5;
var picAmount = 15;
window.onload = function () {
function getClient() {
return {
width: window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth,
height: window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight,
};
}
function getScrollTop() {
return document.documentElement.scrollTop ||
window.pageYOffset ||
document.body.scrollTop;
}
waterFall();
function waterFall() {
var pageWidth = getClient().width;
var itemWidth = items[0].offsetWidth;
var columns = parseInt(pageWidth / (itemWidth + space));
var picList = [];
for (var i = 0; i < items.length; i++) {
if (i < columns) {
items[i].style.top = 0;
items[i].style.left = (itemWidth + space) * i + 'px';
picList.push(items[i].offsetHeight);
} else {
// 找到数组中最小高度的那一列,并拿到其下标
var minHeight = picList[0];
var index = 0;
for (var j = 0; j < picList.length; j++) {
if (minHeight > picList[j]) {
minHeight = picList[j];
index = j;
}
}
items[i].style.top = picList[index] + space + 'px';
items[i].style.left = items[index].offsetLeft + 'px';
// 操作列的高度 = 当前列原本高度 + 图片的高度 + 相邻的间距
picList[index] = picList[index] + items[i].offsetHeight + space;
}
}
}
window.onresize = function () {
waterFall();
};
// 监听滚动事件,模拟懒加载
window.onscroll = function () {
// 如果滚动到的位置比当前显示的最后一个图片高,则请求新的图片
if (
getClient().height + getScrollTop() >=
items[items.length - 1].offsetTop
) {
// 后续的新图片
var datas = [...];
for (var i = 0; i < datas.length; i++) {
picAmount += 1;
var div = document.createElement('div');
div.className = 'item';
div.innerHTML = `<img src="${datas[i]}" alt=""><div>0${picAmount}</div>`;
pic.appendChild(div);
}
waterFall();
}
};
};
</script>
</html>
效果

不同于上面两个 css 实现的瀑布流,JS 实现的图片排序顺序是先水平方向,然后才是垂直方向

可以看到当滚动页面的时候,新的图片会不断添加进来,这样就实现懒加载了
总结
如果实现效果简单不考虑兼容的的话可以选择使用 CSS 实现;若要兼容老版本浏览器或者实现一些个性化的需求还是得用 JS 实现
当然除了上文说的这些方法以外,也可以使用第三方库 Masonry 实现
手摸手,带你实现移动端H5瀑布流布局的更多相关文章
- 手摸手带你学移动端WEB开发
HTML常用标签总结 手摸手带你学CSS HTML5与CSS3知识点总结 手摸手带你学移动端WEB开发 好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/Ro ...
- 【转】手摸手,带你用vue撸后台 系列二(登录权限篇)
前言 拖更有点严重,过了半个月才写了第二篇教程.无奈自己是一个业务猿,每天被我司的产品虐的死去活来,之前又病了一下休息了几天,大家见谅. 进入正题,做后台项目区别于做其它的项目,权限验证与安全性是非常 ...
- 【转】手摸手,带你用vue撸后台 系列三(实战篇)
前言 在前面两篇文章中已经把基础工作环境构建完成,也已经把后台核心的登录和权限完成了,现在手摸手,一起进入实操. Element 去年十月份开始用vue做管理后台的时候毫不犹豫的就选择了Elemen, ...
- 【转】手摸手,带你用vue撸后台 系列一
前言 说好的教程终于来了,第一篇文章主要来说一说在开始写业务代码前的一些准备工作吧,但这里不会教你webpack的基础配置,热更新怎么做,webpack速度优化等等,有需求的请自行google. 目录 ...
- 手摸手带你理解Vue的Computed原理
前言 computed 在 Vue 中是很常用的属性配置,它能够随着依赖属性的变化而变化,为我们带来很大便利.那么本文就来带大家全面理解 computed 的内部原理以及工作流程. 在这之前,希望你能 ...
- 【手摸手,带你搭建前后端分离商城系统】03 整合Spring Security token 实现方案,完成主业务登录
[手摸手,带你搭建前后端分离商城系统]03 整合Spring Security token 实现方案,完成主业务登录 上节里面,我们已经将基本的前端 VUE + Element UI 整合到了一起.并 ...
- 【转】手摸手,带你用vue撸后台 系列四(vueAdmin 一个极简的后台基础模板)
前言 做这个 vueAdmin-template 的主要原因是: vue-element-admin 这个项目的初衷是一个vue的管理后台集成方案,把平时用到的一些组件或者经验分享给大家,同时它也在不 ...
- 原创 | 手摸手带您学会 Elasticsearch 单机、集群、插件安装(图文教程)
欢迎关注笔者的公众号: 小哈学Java, 每日推送 Java 领域干货文章,关注即免费无套路附送 100G 海量学习.面试资源哟!! 个人网站: https://www.exception.site/ ...
- 浅谈Java中的Condition条件队列,手摸手带你实现一个阻塞队列!
条件队列是什么?可能很多人和我一样答不出来,不过今天终于搞清楚了! 什么是条件队列 条件队列:当某个线程调用了wait方法,或者通过Condition对象调用了await相关方法,线程就会进入阻塞状态 ...
随机推荐
- django CBV 及其装饰器
#urls.py from django.contrib import admin from django.urls import path, re_path from app01 import vi ...
- 单片,SOA 和微服务架构有什么区别?
单片架构类似于大容器,其中应用程序的所有软件组件组装在一起并紧密 封装.第一个面向服务的架构是一种相互通信服务的集合.通信可以涉及简单的数 据传递,也可以涉及两个或多个协调某些活动的服务.微服务架构是 ...
- 攻防世界杂项MISCall
MISCall 下载下来是一个附件但是不清楚他是个什么东西我先拉入kali看看 发现是一个tar包不过这个包我们需要使用以下的指令来解压 tar -xjvf d02f31b893164d56b7a8e ...
- 线性二次型控制器(LQR)——轨迹跟踪器
1 概念 2 线性时变系统的跟踪问题 3 线性定常系统的跟踪问题 公式18--22为求解的关键 根据20.21分别求出P.g的值则通过18可求得期望的输出u 4 实例分析 5 仿真实验 先将上 ...
- Linux系统下ifconfig命令使用及结果分析
Linux下网卡命名规律:eth0,eth1.第一块以太网卡,第二块.lo为环回接口,它的IP地址固定为127.0.0.1,掩码8位.它代表你的机器本身. 1.ifconfig是查看网卡的信息. if ...
- 前端性能优化(JavaScript篇)
正巧看到在送书,于是乎找了找自己博客上记录过的一些东西来及其无耻的蹭书了~~~ 小广告:更多内容可以看我的博客 优化循环 如果现在有个一个data[]数组,需要对其进行遍历,应当怎么做?最简单的代码是 ...
- Codepen 每日精选(2018-4-16)
按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以打开原始页面. 内容切换的交互效果https://codepen.io/jcoulterde... 报价卡片的交互效果ht ...
- 用Python爬取斗鱼网站的一个小案例
思路解析: 1.我们需要明确爬取数据的目的:为了按热度查看主播的在线观看人数 2.浏览网页源代码,查看我们需要的数据的定位标签 3.在代码中发送一个http请求,获取到网页返回的html(需要注意的是 ...
- android的布局xml文件如何添加注释?
xml布局文件如图添加注释后报错,错误内容如下: 上网查阅xml添加注释的语法规则: XML 中的注释 在 XML 中编写注释的语法与 HTML 的语法很相似: <!--This is a co ...
- CTF大赛模拟-CFS三层内网漫游
CTF大赛模拟-CFS三层内网漫游 环境: 三台虚拟机,三个网络. target 1:192.168.161.178 ,192.168.52.132 (linux) target 2:192.168. ...