移动端瀑布流布局是一种比较流行的网页布局方式,视觉上来看就是一种像瀑布一样垂直落下的排版。每张图片并不是显示的正正方方的,而是有的长有的短,呈现出一种不规则的形状。但是它们的宽度通常都是相同的

因为移动端瀑布流布局主要为竖向瀑布流,因此本文所探讨的是竖向瀑布流

特点

竖向瀑布流布局主要有下面几种特点:

  • 一般出现在移动端 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

主要思路就是:

  1. 先将第一行排满
  2. 计算第一行的所有图片高度,将第二行第一张图放在第一行最矮的图片后面
  3. 进行玩步骤 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瀑布流布局的更多相关文章

  1. 手摸手带你学移动端WEB开发

    HTML常用标签总结 手摸手带你学CSS HTML5与CSS3知识点总结 手摸手带你学移动端WEB开发 好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/Ro ...

  2. 【转】手摸手,带你用vue撸后台 系列二(登录权限篇)

    前言 拖更有点严重,过了半个月才写了第二篇教程.无奈自己是一个业务猿,每天被我司的产品虐的死去活来,之前又病了一下休息了几天,大家见谅. 进入正题,做后台项目区别于做其它的项目,权限验证与安全性是非常 ...

  3. 【转】手摸手,带你用vue撸后台 系列三(实战篇)

    前言 在前面两篇文章中已经把基础工作环境构建完成,也已经把后台核心的登录和权限完成了,现在手摸手,一起进入实操. Element 去年十月份开始用vue做管理后台的时候毫不犹豫的就选择了Elemen, ...

  4. 【转】手摸手,带你用vue撸后台 系列一

    前言 说好的教程终于来了,第一篇文章主要来说一说在开始写业务代码前的一些准备工作吧,但这里不会教你webpack的基础配置,热更新怎么做,webpack速度优化等等,有需求的请自行google. 目录 ...

  5. 手摸手带你理解Vue的Computed原理

    前言 computed 在 Vue 中是很常用的属性配置,它能够随着依赖属性的变化而变化,为我们带来很大便利.那么本文就来带大家全面理解 computed 的内部原理以及工作流程. 在这之前,希望你能 ...

  6. 【手摸手,带你搭建前后端分离商城系统】03 整合Spring Security token 实现方案,完成主业务登录

    [手摸手,带你搭建前后端分离商城系统]03 整合Spring Security token 实现方案,完成主业务登录 上节里面,我们已经将基本的前端 VUE + Element UI 整合到了一起.并 ...

  7. 【转】手摸手,带你用vue撸后台 系列四(vueAdmin 一个极简的后台基础模板)

    前言 做这个 vueAdmin-template 的主要原因是: vue-element-admin 这个项目的初衷是一个vue的管理后台集成方案,把平时用到的一些组件或者经验分享给大家,同时它也在不 ...

  8. 原创 | 手摸手带您学会 Elasticsearch 单机、集群、插件安装(图文教程)

    欢迎关注笔者的公众号: 小哈学Java, 每日推送 Java 领域干货文章,关注即免费无套路附送 100G 海量学习.面试资源哟!! 个人网站: https://www.exception.site/ ...

  9. 浅谈Java中的Condition条件队列,手摸手带你实现一个阻塞队列!

    条件队列是什么?可能很多人和我一样答不出来,不过今天终于搞清楚了! 什么是条件队列 条件队列:当某个线程调用了wait方法,或者通过Condition对象调用了await相关方法,线程就会进入阻塞状态 ...

随机推荐

  1. PowerDesigner生成MySQL脚本,表和字段进行转义

    打开Power Designer数据库建模工具,软件基本信息如下 如果PowerDesigner内置的(table_option)表物理操作没有,请看以下步骤 打开 Edit Current DBMS ...

  2. TIME_WAIT 优化

    ·[场景描述] HTTP1.1之后,HTTP协议支持持久连接,也就是长连接,优点在于在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟. 如果我们使用了nginx去作为 ...

  3. java后端使用token处理表单重复提交

    保证接口幂等性,表单重复提交 前台解决方案:提交后按钮禁用.置灰.页面出现遮罩后台解决方案:   使用token,每个token只能使用一次1.在调用接口之前生成对应的Token,存放至redis 2 ...

  4. three模型高亮外发光效果

    页面效果如下: vue3+three完整代码如下: <template> </template> <script setup> import * as THREE ...

  5. js技术之根据name获取input的值

    一.前端的代码 <p>Name: <input type='text', name = 'name'/></p> <p>Age: <input t ...

  6. Linux文件管理 | Linux 文件基础知识

    目录 Linux 常用文件类别 Linux 目录结构概述 LInux 系统目录及说明 一.Linux 常用文件类别 1.文件   在Linux上系统上,有一切皆文件的说法,就是说任何软件和I/O设备都 ...

  7. 小程序刷新webview小结

    场景 在小程序其它页面做了操作,数据发生改变,回到webview页面时需要更新webview里面的数据.由于小程序没有提供与webview的实时通信能力,因此刷新页面是个可考虑的做法. 方法一 最常见 ...

  8. [computer vision] Bag of Visual Word (BOW)

    Bag of Visual Word (BoW, BoF, 词袋) 简介 BoW 是传统的计算机视觉方法,用一些特征(一些向量)来表示一个图像.BoW的核心思想是利用一组较为通用的特征,将图像用这些特 ...

  9. 设计模式-观察者模式Observe的实现

    using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> / ...

  10. 从kill-chain的角度检测APT攻击

    前言 最近一直在考虑如何结合kill chain检测APT攻击.出发点是因为尽管APT是一种特殊.高级攻击手段,但是它还是会具有攻击的common feature,只要可以把握住共同特征,就能进行检测 ...