分享一次纯 css 瀑布流 和 js 瀑布流

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

现在百度图片,360 图片搜索,都是以一种瀑布流的形式展示,那么接下来,分享一波纯 css 瀑布流 和 js 瀑布流

纯 css 写瀑布流

multi-columns 方式

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

设置这样的 html 结构:

<div class="masonry"> 
  <div class="item"> 
    <div class="item_content content-lar"> 1 我最大 </div> 
  </div> 
  <div class="item"> 
    <div class="item_content content-sma"> 2 我最小 </div> 
  </div>
  <div class="item"> 
    <div class="item_content content-mid"> 3 我中等 </div> 
  </div>
  <div class="item"> 
    <div class="item_content content-sma"> 4 我最小 </div> 
  </div>
  <div class="item"> 
    <div class="item_content content-mid"> 5 我中等 </div> 
  </div>
  <div class="item"> 
    <div class="item_content content-lar"> 6 我最大 </div> 
  </div>
  <div class="item"> 
    <div class="item_content content-sma"> 7 我最小 </div> 
  </div>
  <div class="item"> 
    <div class="item_content content-lar"> 8 我最大 </div> 
  </div>
  <div class="item"> 
    <div class="item_content content-lar"> 9 我最大 </div> 
  </div>
  <div class="item"> 
    <div class="item_content content-sma"> 10 我最小 </div> 
  </div>
  <div class="item">
    <div class="item_content content-mid"> 11 我中等 </div> 
  </div>
  <div class="item"> 
    <div class="item_content content-mid"> 12 我中等 </div> 
  </div>
  <!-- more items --> 
</div>

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

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

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

.masonry { 
  -moz-column-count:3; /* Firefox */
  -webkit-column-count:3; /* Safari 和 Chrome */
  column-count:3;
  -moz-column-gap: 2em;
  -webkit-column-gap: 2em;
  column-gap: 2em;
  width: 70%;
  margin:2em auto;
}
.item { 
  padding: 2em;
  margin-bottom: 2em;
  -moz-page-break-inside: avoid;
  -webkit-column-break-inside: avoid;
  break-inside: avoid;
  background: #f60;
  color: #fff;
  text-align: center;
}
.item .content-lar {
  height: 200px;
}
.item .content-mid {
  height: 100px;
}
.item .content-sma {
  height: 50px;
}

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

@media screen and (max-width: 800px) { 
  .masonry { 
    column-count: 2; /* two columns on larger phones */
  } 
} 
@media screen and (max-width: 500px) { 
  .masonry { 
    column-count: 1; /* two columns on larger phones */
  }
}

那么以上代码产生的效果是:

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

flexbox 方式 (flex布局)

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

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

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

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

.masonry { 
  height: 800px;
  display: flex; 
  flex-flow: column wrap;
  width: 70%;
  margin:2em auto;
}
.item { 
  padding: 2em;
  margin-bottom: 2em;
  break-inside: avoid;
  background: #f60;
  color: #fff;
  text-align: center;
  margin: 10px;
}
.item .content-lar {
  height: 200px;
}
.item .content-mid {
  height: 100px;
}
.item .content-sma {
  height: 50px;
}

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

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

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

@media screen and (max-width: 1100px) { 
  .masonry { 
    height: 800px; 
  } 
}
@media screen and (max-width: 800px) {
  .masonry { 
    height: 1100px; 
  } 
} 
@media screen and (max-width: 600px) { 
  .masonry { 
    height: 1300px; 
  } 
} 
@media screen and (max-width: 460px) { 
  .masonry { 
    height: 1600px;
  } 
}

那么所产生的效果是:

问题来了

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

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

我们想要的是这样:

要实现如上,只能通过 js 来写瀑布流

js 写瀑布流

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

<div class="masonry"> 
  <div class="item"> 
    <img class="lazy" src="images/1.jpg" alt="" />
  </div> 
  <div class="item"> 
    <img class="lazy" src="images/2.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/3.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/4.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/5.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/6.jpg" alt="" />
  </div> 
  <div class="item"> 
    <img class="lazy" src="images/7.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/8.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/9.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/10.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/11.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/12.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/13.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/14.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/15.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/16.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/17.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/18.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/19.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/20.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/21.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/22.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/23.jpg" alt="" />
  </div>
  <div class="item"> 
    <img class="lazy" src="images/24.jpg" alt="" />
  </div>
</div>

css 内容

.masonry { 
  width: 100%;
  margin-top: 50px;
  position:relative;
}
.item { 
  z-index: 10;
  transition: 0.25s;
  overflow: hidden;
  position: absolute;
}
.item img{
  width: 100%;
  height:100%;
  transition: 0.25s;
}
.item:hover img{
  z-index: 100;
  transition: 0.25s;
  overflow: hidden;
  animation: bounceIn 0.25s ease-in 2 alternate;
}
@keyframes bounceIn{
  100% {
    transform: scale(1.07);
  }
}

重点:js 瀑布流实现方式

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

// 瀑布流效果
// 这里有一个坑(已经修复):
// 因为是动态加载远程图片,在未加载完全无法获取图片宽高
// 未加载完全就无法设定每一个 item(包裹图片)的 top。

// item 的 top 值:第一行:top 为 0
//            其他行:必须算出图片宽度在 item 宽度的缩小比例,与获取的图片高度相乘,从而获得 item 的高度
//                   就可以设置每张图片在瀑布流中每块 item 的 top 值(每一行中最小的 item 高度,数组查找)
// item 的 left 值:第一行:按照每块 item 的宽度值*块数
//            其他行:与自身上面一块的 left 值相等
function waterFall () {
  // 1- 确定图片的宽度 - 滚动条宽度
  var pageWidth = getClient().width-8;
  var columns = 3; // 3 列
  var itemWidth = parseInt(pageWidth/columns); // 得到item的宽度
  $(".item").width(itemWidth); // 设置到item的宽度
  
  var arr = [];

  $(".masonry .item").each(function(i){
    var height = $(this).find("img").height();
    var width = $(this).find("img").width();
    var bi = itemWidth/width; // 获取缩小的比值
    var boxheight = parseInt(height*bi); // 图片的高度*比值 = item的高度

    if (i < columns) {
      // 2- 确定第一行
      $(this).css({
        top:0,
        left:(itemWidth) * i
      });
      arr.push(boxheight);

    } else {
      // 其他行
      // 3- 找到数组中最小高度  和 它的索引
      var minHeight = arr[0];
      var index = 0;
      for (var j = 0; j < arr.length; j++) {
        if (minHeight > arr[j]) {
          minHeight = arr[j];
          index = j;
        }
      }
      // 4- 设置下一行的第一个盒子位置
      // top值就是最小列的高度 
      $(this).css({
        top:arr[index],
        left:$(".masonry .item").eq(index).css("left")
      });

      // 5- 修改最小列的高度 
      // 最小列的高度 = 当前自己的高度 + 拼接过来的高度
      arr[index] = arr[index] + boxheight;
    }
  });
}


// clientWidth 处理兼容性
function getClient() {
  return {
    width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
    height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
  }
}



 // 页面尺寸改变时实时触发
window.onresize = function() {
  // 重新定义瀑布流
  waterFall();
};



// 初始化
window.onload = function(){
  
  // 实现瀑布流
  waterFall();

}

大功告成,效果图是

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

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏LIN_ZONE

css 中 zoom和transform:scale的区别(转载)

还在几年前,zoom还只是IE浏览器自己私有的玩具,但是,现在,除了FireFox浏览器,其他,尤其Chrome和移动端浏览器已经很好支持zoom属性了:

11630
来自专栏前端知识分享

第54天:原生js实现轮播图效果

一系列的大小相等的图片平铺,利用CSS布局只显示一张图片,其余隐藏。通过计算偏移量利用定时器实现自动播放,或通过手动点击事件切换图片。

53210
来自专栏企鹅号快讯

Web前端:浅析“HTML+CSS的基本应用”

Hyper Text Markup Language,简称HTML,超文本标记语言,因页面中可以包含图片、链接、音乐、程序等非文本元素,所以称为超文本。 ? H...

243100
来自专栏24K纯开源

用Qt写软件系列四:定制个性化系统托盘菜单

导读     一款流行的软件,往往会在功能渐趋完善的时候,通过改善交互界面来提高用户体验。毕竟,就算再牛逼的产品,躲藏在糟糕的用户界面之后总会让用户心生不满。界...

413100
来自专栏编程微刊

用Canvas画一个刮刮乐

21540
来自专栏守候书阁

CSS3热身实战--过渡与动画(实现炫酷下拉,手风琴,无缝滚动)

在自己的专栏上写了十几篇文章了,都是与js有关的。暂时还没有写过关于css3的文章。css3,给我的感觉就是,不难,但是很难玩转自如。今天,就用css3来实现三...

61640
来自专栏袁佳平的专栏

周杰伦读心术背后的技术实现

前言   在技术细节的内容开始之前,您可以先通过下方的二维码再次体验这个魔术。 image.png image.png 一、HTML 1.设置meta <m...

75780
来自专栏小筱月

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

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

90620
来自专栏前端说吧

css3-巧用选择器 “:target”

37160
来自专栏葡萄城控件技术团队

给萌新的Flexbox简易入门教程

近几年,CSS领域出现了一些复杂的专用布局工具,用以代替原有的诸如使用表格、浮动和绝对定位之类的各种变通方案。Flexbox,或者说是弹性盒子布局模块(Flex...

9420

扫码关注云+社区

领取腾讯云代金券