• 《uni-app》移动端纯CSS实现不等高的瀑布流效果


    在这里插入图片描述

    前言

    前两天无意中看到朋友在玩小红书,第一眼就被其瀑布流的布局给吸引住了,感觉非常有意思,之前知道有这种布局,但大多数都是在web端,移动端上还是首次见到,因此特别想试试~
    这一章节,玩一点好玩的,移动端或者直接说uni-app能否使用 纯CSS 实现瀑布流的布局效果~ 我们知道,不等高的瀑布流布局可以给用户造成视觉上的错位,非常具有美感,实际上绝大多数项目中的的瀑布流都是借助于JavaScript实现的,通过JavaScript动态计算每一个DOM的尺寸与坐标,最终实现布局,毫无疑问,这种就是目前的最优解;
    但是,布局这东西不应该是CSS的领域么,那么 纯CSS 能不能实现呢,我觉得是可以的,虽然有不少问题无法解决…

    示例

    可能会有小伙伴问,什么是瀑布流布局,简单看两种示例吧,一看就明白了的

    WEB端示例

    在这里插入图片描述

    移动端示例

    在这里插入图片描述
    这种就是不等高的瀑布流布局,还是比较一目了然的;

    瀑布流实现

    先看一下原始状态吧,原始状态的图片效果如下
    在这里插入图片描述

    第一种: flex

    flex布局作为现代前端开发最常用的布局方式,那么flex能不能实现瀑布流呢,答案是可以的,虽然不完美,但确实是实现了

    核心代码

    核心利用的就是 flex的纵向布局,以及当超出高度时自动换行,也就是这两行代码

    flex-direction: column;
    flex-wrap: wrap;
    
    • 1
    • 2

    以及当纵向排序而非横向排序时必须借助 order属性进行重新排序;

    order:1
    
    • 1

    实现

    我们知道,flex 默认时沿着X轴进行排布的,并且超出后也不会换行,即是设置了flex-wrap: wrap; 也是这种,如下图展示
    在这里插入图片描述
    并且,还会有一个致命的问题,即同一行的高度是保持一致的,它并 不会因为其中一张高度低下方的图片就自动补上空缺的位置,具体细节可以参考下图
    在这里插入图片描述
    既然不会自动补上空缺,那是不是就没办法了,那肯定不是,我们不妨换个思路,flex在同一行内会不断的往前顶补空位,那是不是代表如果纵向排列,一列之间会不断的往上补位,因为一列等同于横着时候的一行,那么结果就会变成 不同列之间的起始的位置是同一个水平的,但同一列之内它不会有空隙,对代码尝试了修改,加添方向后的代码如下:

    <template>
    	<view class="content">
    		  <view class="img-container" v-for="(item,index) in list" :key="index">
    		    <img class="img-style" :src="item.src" :style="{height:item.height}" />
    			<div>
    				标题{{index}}
    			</div>
    		  </view>
    	</view>
    </template>
    <style>
    	.content {
    		display: flex;
    		flex-direction: column;
    		flex-wrap: wrap; 
    	}
    	.img-container{
    		position: relative;
    		
    		width: 375rpx;
    		padding-bottom: 0;
    		box-sizing: border-box;
    	}
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    编写代码后发现,这么写的 图片超出屏幕后并没有自动新开启一列,而是有多少张图片,这一列就有多高
    在这里插入图片描述
    我们不能让他无限变高,必须限定一个高度,只有限定了高度,超出时才会自动新起一列,我们给父级容器加上个高度 height

    <style>
    	.content {
    		display: flex;
    		flex-direction: column;
    		flex-wrap: wrap; 
    		height: 1100px;
    	}
    	.img-container{
    		position: relative;
    		
    		width: 375rpx;
    		padding-bottom: 0;
    		box-sizing: border-box;
    	}
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    得到结果如下:
    在这里插入图片描述
    看起来有点相像了,但是我们知道,这个图片它是纵向排列的,就如上图中的线条图那种,不信我们可以标签看一下,加上如下CSS代码

    .img-container{
      position: relative;
      
      width: 375rpx;
      padding-bottom: 0;
      box-sizing: border-box;
      
      counter-increment: item-counter;
    }
    .img-container::after{
      position: absolute;
      top: 10rpx;
      right: 10rpx;
      
      display: block;
      width: 30px;
      height: 30px;
      
      text-align: center;
      line-height: 30px;
      background-color: #000;
      color: #fff;
      content:counter(item-counter);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    加上后,我们可以得到一个标签,如下图所示(因为标题的文字还需要排版,所以先去掉了)
    在这里插入图片描述
    确实是纵向排列的,但 理论上我们需要的是横向排列,我们得找一个办法将这个 布局方式改为横向排列,那必须要借助一个叫 order 的值了

    order 属性 设置或检索弹性盒模型对象的子元素出现的順序。

    因此,借助 order属性 我们可以给所有的 img-container 按照比例进行排序(注意,这个属性只对flex布局生效),也就是如下

    .img-container:nth-child(2n+1){
      order: 1;
    }
    .img-container:nth-child(2n){
      order: 2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    得到效果图如下:
    在这里插入图片描述

    缺点

    至于缺陷,自然是有的,其实我们一开始就说了,一切的一切都 必须借助于flex容器高度固定这个基础上,如果这个值没有,下面这些实现都是不可能的,如果实际项目中想要用flex实现瀑布流布局,那么 一定要对高度进行精确的计算,否则很容易出现图片叉了的情况,比如出现了第三列这种,完全超出了预期…

    完整代码

    <template>
    	<view class="content">
    		  <view class="img-container" v-for="(item,index) in list" :key="index" >
    		    <img class="img-style" :src="item.src" :style="{height:item.height}" />
    		  </view>
    	</view>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    				title: 'Hello',
    				list:[
    					{
    						src:"https://picsum.photos/300/400?random=1",
    						height:"180px"
    					},{
    						src:"https://picsum.photos/300/420?random=2",
    						height:"220px"
    					},{
    						src:"https://picsum.photos/300/460?random=3",
    						height:"240px"
    					},{
    						src:"https://picsum.photos/300/380?random=4",
    						height:"160px"
    					},{
    						src:"https://picsum.photos/300/420?random=5",
    						height:"220px"
    					},{
    						src:"https://picsum.photos/300/440?random=6",
    						height:"260px"
    					},{
    						src:"https://picsum.photos/300/500?random=7",
    						height:"220px"
    					},{
    						src:"https://picsum.photos/300/490?random=8",
    						height:"200px"
    					}
    				]
    			}
    		},
    	}
    </script>
    
    <style>
    	.content {
    		display: flex;
    		flex-direction: column;
    		flex-wrap: wrap; 
    		height: 1100px;
    	}
    	.img-container{
    		position: relative;
    		
    		width: 375rpx;
    		padding-bottom: 0;
    		box-sizing: border-box;
    		
    		counter-increment: item-counter;
    	}
    	.img-container:nth-child(2n+1){
    		padding-left: 10rpx;
    		padding-right: 5rpx;
    	}
    	.img-container:nth-child(2n){
    		padding-left: 5rpx;
    		padding-right: 10rpx;
    	}
    	.img-container .img-style{
    		width: 100%;
    	}
    	.img-container::after{
    		position: absolute;
    		top: 10rpx;
    		right: 10rpx;
    		
    		display: block;
    		width: 30px;
    		height: 30px;
    		
    		text-align: center;
    		line-height: 30px;
    		background-color: #000000;
    		color: #ffffff;
    		content:counter(item-counter);
    	}
    	.img-container:nth-child(2n+1){
    		order: 1;
    	}
    	.img-container:nth-child(2n){
    		order: 2;
    	}
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    第二种:column-count及column-gap

    这两个属性…我相信可能好多人都没有见过…简单的介绍一下吧,column-count,这是一个CSS3的属性,官方说明如下:

    column-count CSS 属性,描述元素的列数。

    简单的说,它的作用只有一个,指定某个元素内部应当分为几列,就这么简单粗暴,而 column-gap 的官方说明如下:

    CSS column-gap 属性用来设置元素列之间的间隔(gutter)大小。

    这个属性得和 column-count 配合使用,作用就是 指定列于列之间的间隔宽度,这两个属性对兼容性还是由一些要求的,但好在移动端的容器版本都不会老,因此 如果仅在移动端使用,还是有些可行性的~

    核心代码

    column-count: 2;
    column-gap: 0;
    
    • 1
    • 2

    核心代码就这两行,一行申明几列,一行声明间隔;

    实现

    依旧是上一节中的原始代码,我们只需要在父容器加上这两行代码

    .content {
      column-count: 2;
      column-gap: 0;
    }
    
    • 1
    • 2
    • 3
    • 4

    就会得到如下结果
    在这里插入图片描述
    是不是已经非常像了,而且比 flex布局还要简单,毕竟只有2行代码,那么排列方向呢?很遗憾,还是纵向排列的,我们加上上一节中的伪类,对每张图片进行一个标记,得到如下结果
    在这里插入图片描述
    有没有办法改为横向排列呢,好像是没有,至少博主没有找到,order 这个属性是针对 flex 的,普通的盒模型并不会生效

    缺点

    缺点很明显了,就是排列顺序 仅仅支持纵向排列,它不支持横向,和 flex布局 相对,优点就是实现简单,也不需要计算高度

    完整代码

    <template>
    	<view class="content">
    		  <view class="img-container" v-for="(item,index) in list" :key="index" >
    		    <img class="img-style" :src="item.src" :style="{height:item.height}" />
    		  </view>
    	</view>
    </template>
    
    <script>
    	export default {
    		data() {
    			return {
    				title: 'Hello',
    				list:[
    					{
    						src:"https://picsum.photos/300/400?random=1",
    						height:"180px"
    					},{
    						src:"https://picsum.photos/300/420?random=2",
    						height:"220px"
    					},{
    						src:"https://picsum.photos/300/460?random=3",
    						height:"240px"
    					},{
    						src:"https://picsum.photos/300/380?random=4",
    						height:"160px"
    					},{
    						src:"https://picsum.photos/300/420?random=5",
    						height:"220px"
    					},{
    						src:"https://picsum.photos/300/440?random=6",
    						height:"260px"
    					},{
    						src:"https://picsum.photos/300/500?random=7",
    						height:"220px"
    					},{
    						src:"https://picsum.photos/300/490?random=8",
    						height:"200px"
    					}
    				]
    			}
    		},
    	}
    </script>
    
    <style>
    	.content {
    		column-count: 2;
    		column-gap: 0;
    	}
    	.img-container{
    		position: relative;
    		
    		width: 375rpx;
    		padding: 4px;
    		padding-bottom: 0;
    		box-sizing: border-box;
    		
    		counter-increment: item-counter;
    	}
    	.img-container .img-style{
    		width: 100%;
    	}
    	.img-container::after{
    		position: absolute;
    		top: 10rpx;
    		right: 10rpx;
    		
    		display: block;
    		width: 30px;
    		height: 30px;
    		
    		text-align: center;
    		line-height: 30px;
    		background-color: #000000;
    		color: #ffffff;
    		content:counter(item-counter);
    	}
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    小结

    本文分享了 两种实现瀑布流布局的纯CSS办法,他们各有优缺点,大致如下:

    • flex:支持横向排序,但父容器必须计算高度,而且是精准的高度,没有高度,那么布局将实现不了
    • column不支持横向排序,实现有效并且非常简单;

    (PS:都已经看到这里了,点个赞,求个关注吧,万分感谢~)

  • 相关阅读:
    APScheduler如何设置任务不并发(即第一个任务执行完再执行下一个)?
    Faster R-CNN pytorch版
    合肥先进光源国家重大科技基础设施项目及配套工程启动会纪念
    Redis中的Lua脚本(六)
    `算法竞赛题解` `LeetCode` 1044. 最长重复子串
    简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
    学习笔记-TP5框架学习笔记进阶之Contorller
    7款三维地球软件/框架:Google Earth SkylineGlobe,Cesium等
    rabbitMQ的direct模式的生产者与消费者使用案例
    EasyCVR平台添加RTSP设备时,出现均以TCP方式连接的现象是什么原因?
  • 原文地址:https://blog.csdn.net/zy21131437/article/details/126450691