浅谈瀑布流

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈瀑布流相关的知识,希望对你有一定的参考价值。

参考技术A

瀑布流又称瀑布流式布局,是比较流行的一种网站页面布局方式。视觉表现为参差不齐的多栏布局,最早采用此布局的是网站是 Pinterest,后逐渐在国内流行。

即多行等宽元素排列,后面的元素依次添加到其后,等宽不等高,根据图片原比例缩放直至宽度达到我们的要求,依次按照规则放入指定位置。

那么规则是什么呢?
下面通过图解来分析一下瀑布流的算法。

当第一排排满足够多的等宽图片时(如下图情况),自然而然的考虑到之后放置的图片会往下面排放。

那么第六张图片,放置在什么位置呢?是下图的位置么?

我们通过瀑布流算法实验得到,后面紧跟的第六张图片的位置应该是这个位置。

为什么呢?
因为放置它之前,这一列的高度为所有列中最小,所以会放置在这个地方。
所以我们知道了,如果再继续放置下去,第七张图片应该是这个位置,对吗?

通过瀑布流算法实验得出位置正确。看懂这个图示应该就能理解了瀑布流的原理算法。


这里使用了jQuery


瀑布流 Demo 效果



瀑布流 + 懒加载 实现新闻站
https://github.com/evenyao/waterfall-sinanews

分享:纯 css 瀑布流 和 js 瀑布流

 博客地址:https://ainyi.com/60

 

纯 css 写瀑布流

1.multi-columns 方式:

通过 Multi-columns 相关的属性 column-countcolumn-gap 配合 break-inside 来实现瀑布流布局。

设置这样的 html 结构:

 1             <div class="masonry"> 
 2             <div class="item"> 
 3                 <div class="item_content content-lar"> 1
 4                 </div> 
 5             </div> 
 6             <div class="item"> 
 7                 <div class="item_content content-sma"> 2
 8                 </div> 
 9             </div>
10             <div class="item"> 
11                 <div class="item_content content-mid"> 3
12                 </div> 
13             </div>
14             <div class="item"> 
15                 <div class="item_content content-sma"> 4
16                 </div> 
17             </div>
18             <div class="item"> 
19                 <div class="item_content content-mid"> 5
20                 </div> 
21             </div>
22             <div class="item"> 
23                 <div class="item_content content-lar"> 6
24                 </div> 
25             </div> 
26             <div class="item"> 
27                 <div class="item_content content-sma"> 7
28                 </div> 
29             </div>
30             <div class="item"> 
31                 <div class="item_content content-lar"> 8
32                 </div> 
33             </div>
34             <div class="item"> 
35                 <div class="item_content content-lar"> 9
36                 </div> 
37             </div>
38             <div class="item"> 
39                 <div class="item_content content-sma"> 10
40                 </div> 
41             </div>
42             <div class="item"> 
43                 <div class="item_content content-mid"> 11
44                 </div> 
45             </div>
46             <div class="item"> 
47                 <div class="item_content content-mid"> 12
48                 </div> 
49             </div>
50             <!-- more items --> 
51         </div>            

 

.masonry 是瀑布流容器,里面放置了列表 item,在 .masonry 中设置 column-count(列数) 和 column-gap(列间距)

item 中设置 break-inside:avoid,这是为了控制文本块分解成单独的列,以免项目列表的内容跨列,破坏整体的布局。

在 css 中设置包裹 masonry 和 item 的属性样式:

 1             .masonry { 
 2                 -moz-column-count:3; /* Firefox */
 3                 -webkit-column-count:3; /* Safari 和 Chrome */
 4                 column-count:3;
 5                 -moz-column-gap: 2em;
 6                 -webkit-column-gap: 2em;
 7                 column-gap: 2em;
 8                 width: 80%;
 9                 margin:2em auto;
10             }
11             .item { 
12                 padding: 2em;
13                 margin-bottom: 2em;
14                 -moz-page-break-inside: avoid;
15                 -webkit-column-break-inside: avoid;
16                 break-inside: avoid;
17                 background: #f60;
18             }

 

当然为了布局具有响应式效果,可以借助媒体查询属性,在不同屏幕大小的条件下设置瀑布流容器 masonry 的 column-count 来自适应改变列数

 1             @media screen and (max-width: 800px) { 
 2                 .masonry { 
 3                     column-count: 2; // two columns on larger phones 
 4                 } 
 5             } 
 6             @media screen and (max-width: 500px) { 
 7                 .masonry { 
 8                     column-count: 1; // two columns on larger phones 
 9                 } 
10             } 

 

那么所产生的效果是:

也是根据屏幕大小自适应改变列数

 

2.flexbox 方式:

html 的结构依旧和上面的 Multi-columns 展示的一样。只是在 .masonry 容器中使用的 CSS 不一样:

在 .masonry 中是通过采用 flex-flow 来控制列,并且允许它换行。

这里关键是容器的高度,我这里要显式的设置 height 属性,当然除了设置 px 值,还可以设置100vh,让 .masonry 容器的高度和浏览器视窗高度一样。

记住,这里height可以设置成任何高度值(采用任何的单位),但不能不显式的设置,如果没有显式的设置,容器就无法包裹住项目列表。

1             .masonry { 
2                 height: 800px;
3                 display: flex; 
4                 flex-flow: column wrap;
5                 width: 80%;
6                 margin:2em auto;
7             }

 

对于 .item,可以不再使用 break-inside:avoid,但其它属性可以是一样。

同样的,响应式设置,使用 Flexbox 实现响应式布局比多列布局 Multi-columns 要来得容易,他天生就具备这方面的能力,只不过我们这里需要对容器的高度做相关的处理。

前面也提到过了,如果不给 .masonry 容器显式设置高度是无法包裹项目列表的,那么这里响应式设计中就需要在不同的媒体查询条件下设置不同的高度值:

 1             @media screen and (max-width: 1100px) { 
 2                 .masonry { 
 3                     height: 800px; 
 4                 } 
 5             }
 6             @media screen and (max-width: 800px) {
 7                 .masonry { 
 8                     height: 1100px; 
 9                 } 
10             } 
11             @media screen and (max-width: 600px) { 
12                 .masonry { 
13                     height: 1300px; 
14                 } 
15             } 
16             @media screen and (max-width: 460px) { 
17                 .masonry { 
18                     height: 1600px;
19                 } 
20             } 

 

那么所产生的效果是:

也是根据屏幕大小自适应改变列数。

 

看到这里,我们可以发现,使用纯 css 写瀑布流,每一块 item 都是从上往下排列,不能做到从左往右排列:

 

 

这样子若是动态加载图片的瀑布流,体验就会很不好

我们想要的是这样:

 

这样做只能通过 js 来写瀑布流

 

js 写瀑布流:

html 结构与上面类似,这里我用图片来做示例:

 1         <div class="masonry"> 
 2             <div class="item"> 
 3                 <img class="lazy" src="images/1.jpg" alt="" />
 4             </div> 
 5             <div class="item"> 
 6                 <img class="lazy" src="images/2.jpg" alt="" />
 7             </div>
 8             <div class="item"> 
 9                 <img class="lazy" src="images/3.jpg" alt="" />
10             </div>
11             <div class="item"> 
12                 <img class="lazy" src="images/4.jpg" alt="" />
13             </div>
14             <div class="item"> 
15                 <img class="lazy" src="images/5.jpg" alt="" />
16             </div>
17             <div class="item"> 
18                 <img class="lazy" src="images/6.jpg" alt="" />
19             </div> 
20             <div class="item"> 
21                 <img class="lazy" src="images/7.jpg" alt="" />
22             </div>
23             <div class="item"> 
24                 <img class="lazy" src="images/8.jpg" alt="" />
25             </div>
26             <div class="item"> 
27                 <img class="lazy" src="images/9.jpg" alt="" />
28             </div>
29             <div class="item"> 
30                 <img class="lazy" src="images/10.jpg" alt="" />
31             </div>
32             <div class="item"> 
33                 <img class="lazy" src="images/11.jpg" alt="" />
34             </div>
35             <div class="item"> 
36                 <img class="lazy" src="images/12.jpg" alt="" />
37             </div>
38             <div class="item"> 
39                 <img class="lazy" src="images/13.jpg" alt="" />
40             </div>
41             <div class="item"> 
42                 <img class="lazy" src="images/14.jpg" alt="" />
43             </div>
44             <div class="item"> 
45                 <img class="lazy" src="images/15.jpg" alt="" />
46             </div>
47             <div class="item"> 
48                 <img class="lazy" src="images/16.jpg" alt="" />
49             </div>
50             <div class="item"> 
51                 <img class="lazy" src="images/17.jpg" alt="" />
52             </div>
53             <div class="item"> 
54                 <img class="lazy" src="images/18.jpg" alt="" />
55             </div>
56             <div class="item"> 
57                 <img class="lazy" src="images/19.jpg" alt="" />
58             </div>
59             <div class="item"> 
60                 <img class="lazy" src="images/20.jpg" alt="" />
61             </div>
62             <div class="item"> 
63                 <img class="lazy" src="images/21.jpg" alt="" />
64             </div>
65             <div class="item"> 
66                 <img class="lazy" src="images/22.jpg" alt="" />
67             </div>
68             <div class="item"> 
69                 <img class="lazy" src="images/23.jpg" alt="" />
70             </div>
71             <div class="item"> 
72                 <img class="lazy" src="images/24.jpg" alt="" />
73             </div>
74         </div>

 

css 内容:

 1             .masonry { 
 2                 width: 100%;
 3                 margin-top: 50px;
 4                 position:relative;
 5             }
 6             .item { 
 7                 z-index: 10;
 8                 transition: 0.25s;
 9                 overflow: hidden;
10                 position: absolute;
11             }
12             .item img{
13                 width: 100%;
14                 height:100%;
15                 transition: 0.25s;
16             }
17             .item:hover img{
18                 z-index: 100;
19                 transition: 0.25s;
20                 overflow: hidden;
21                 animation: bounceIn 0.25s ease-in 2 alternate;
22             }
23             @keyframes bounceIn{
24                 100% {
25                     transform: scale(1.07);
26                 }
27             }

 

js 瀑布流实现方式:

css 的绝对定位方式:根据每张图片的位置设置 top 和 left 值:

 1 //瀑布流效果
 2 //这里有一个坑(已经修复):
 3 //因为是动态加载远程图片,在未加载完全无法获取图片宽高
 4 //未加载完全就无法设定每一个item(包裹图片)的top。
 5 
 6 //item的top值:第一行:top为0
 7 //            其他行:必须算出图片宽度在item宽度的缩小比例,与获取的图片高度相乘,从而获得item的高度
 8 //                   就可以设置每张图片在瀑布流中每块item的top值(每一行中最小的item高度,数组查找)
 9 //item的left值:第一行:按照每块item的宽度值*块数
10 //             其他行:与自身上面一块的left值相等
11 function waterFall() {
12     // 1- 确定图片的宽度 - 滚动条宽度
13     var pageWidth = getClient().width-8;
14     var columns = 3; //3列
15     var itemWidth = parseInt(pageWidth/columns); //得到item的宽度
16     $(".item").width(itemWidth); //设置到item的宽度
17     
18     var arr = [];
19 
20     $(".masonry .item").each(function(i){
21         var height = $(this).find("img").height();
22         var width = $(this).find("img").width();
23         var bi = itemWidth/width; //获取缩小的比值
24         var boxheight = parseInt(height*bi); //图片的高度*比值 = item的高度
25 
26         if (i < columns) {
27             // 2- 确定第一行
28             $(this).css({
29                 top:0,
30                 left:(itemWidth) * i
31             });
32             arr.push(boxheight);
33 
34         } else {
35             // 其他行
36             // 3- 找到数组中最小高度  和 它的索引
37             var minHeight = arr[0];
38             var index = 0;
39             for (var j = 0; j < arr.length; j++) {
40                 if (minHeight > arr[j]) {
41                     minHeight = arr[j];
42                     index = j;
43                 }
44             }
45             // 4- 

以上是关于浅谈瀑布流的主要内容,如果未能解决你的问题,请参考以下文章

Android图片瀑布流怎么实现

瀑布流实现思路

Dreamweaver 怎么实现瀑布流

css瀑布流间距不对

Android实现自动滚动的瀑布流?怎么实现

分享:纯 css 瀑布流 和 js 瀑布流