用Masonry和jQuery.lazyload插件实现网页瀑布流布局

瀑布流布局

我们常能在网上看到很多瀑布流布局的页面,尤其是很多图片网站,例如百度图片。这种最典型的瀑布流布局,每个元素的宽度是固定的,但图片长度各不相同,于是通过下图这种样子竖着排列了下来,达到了最大的页面空间利用率。

因为对前端开发不了解,一开始为了找到这种布局叫什么名字也是花了我好久时间o(╯□╰)o

瀑布流布局不局限于等宽布局,例如下面这种形式也可以,来自Masonry官网截图。

Masonry官网 http://masonry.desandro.com/

瀑布流布局作为一种响应式布局,网页元素会自动根据页面宽度进行调整。按住Ctrl键并滚动鼠标滚轮,对网页进行缩放,我们就能看到网页元素之间的排版位置会不断变化,如上图所示。

瀑布流布局实现

对于上面的等宽瀑布流布局,看起来其实似乎很容易实现。但是由于HTML文档流的原理,网页元素的排列是先从左往右的,超出了才会换行,而不能直接控制成从上往下,因此直接利用HTML和CSS不太好处理,完美的瀑布流布局需要借助javascriptjQuery插件实现。这里说的不是很清楚,可以看下文中详细的图文解释。瀑布流布局的实现有很多种方式,这篇文章写得也很详细。

瀑布流布局浅析 http://ued.taobao.org/blog/2011/09/waterfall/

Masonry插件

Masonry插件是用的比较多的瀑布流布局插件。下面两张图展示了插件使用前后的网页布局,很容易看出其作用。

没使用Masonry时,网页元素按照HTML文档流排列,先从左到右,超出再换行,中间会有很多空隙,如下图所示。

使用了Masonry之后,每个元素位置会自动被调整,空隙少了很多,如图所示。

Masonry的基本使用

Masonry插件有两个版本,一个用的原生javascript,一个用的jQuery,如果你的网页刚好用到了其他jQuery库,建议用后者,因为代码量会少很多。两个版本的插件都可以在附件中的Demo里找到。

Masonry官方GitHub链接(JavaScript版本,含多个Demo示例)
https://github.com/desandro/masonry

jQuery Masonry也可在此下载(不知道这个站点算不算官网,感觉有点乱)
http://www.fishspotr.com

Masonry插件的使用很简单,但是官方GitHub给出的Demo里面代码太长不容易看明白,所以我提供了一个简化的Demo,使用了最常用的几个参数。具体的参数可以参考官方的Demo。

调用Masonry的代码可以写在<script>标签中,也可以直接写在HTML标签的data-masonry-options属性中,我提供的javascript版本的代码就写在了data-masonry-options属性中。

另外网上的很多文档都有错,都是套用官方的文档,把两个版本混为一谈。例如jQueryjavascript版本有一些参数是不一样的,例如javascript版本中的gutter参数在jQuery版本里面是gutterWidth,这个可以从源码中看到(也可能是版本升级改了参数名)。

Lazyload延迟加载图片

网页中常用Lazyload插件进行图片的延迟加载,用户滚动页面,要浏览到图片所在的位置时,才开始加载图片,否则不加载。一方面能加快网页刚刚载入时的速度,因为省去了很多图片的加载;另一方面能节省流量,因为只需要加载用户滚动到的地方的图片,如果用户中途离开页面,部分图片就不会被加载了。

这里顺便提一下Lazyload,使用这个插件时,IMG标签需要写成这种形式:<img src="loading.gif" data-original="img.jpg" />,src中是一个体积较小的占位图片,而真实图片地址写在后面的data-original属性中。网上有人说的Lazyload不能用、有bug,就是因为这个地方没有写好。

另外,为了防止有些用户浏览器没开javascript,上面这样写会导致图片不显示,因此稳妥起见还有必要添加一个<noscript>标签,在里面写上正常的图片标签,没有javascript时这段代码就会生效,如下所示。

  1. <img src="loading.gif" data-original="img.jpg" />
  2. <noscript><img src="img.jpg" /></noscript>

Masonry与Lazyload插件冲突

同时使用MasonryLazyload插件,会造成冲突。因为Masonry需要获取每个元素的尺寸从而计算出元素的位置,但是在网页滚动过程中,由于Lazyload动态加载图片会导致元素尺寸变化,而此时Masonry并不会重新计算,于是排列就混乱了,如图所示。

解决思路是每次Lazyload加载好一张图片就让Masonry重新排版。但找了很久也没找到Lazyload的回调参数……

先后考虑或尝试了滚动网页事件、IMG加载完成事件、DIV尺寸变化事件、延时等来触发Masonry,还考虑过提前在后台计算好图片标签的尺寸、把Lazyload换成其他插件,但是怎么做都感觉不好,效率低或是很麻烦等问题。

最后感觉最好的办法还是干脆自己改一下Lazyload的源码好了。但在看源码的时候意外发现了Lazyload其实有回调函数,也就是load参数。

网上大量文章都是复制粘贴来的一摸一样的几句话,甚至连官方也都没有说这个参数……莫非是我的打开方式不对?

我眼里的Lazyload官网 http://www.appelsiini.net/projects/lazyload

最后的解决方案就很清楚了,关键代码大致如下。示例Demo也在附件中。

  1. <script>

  2. $(function() {

  3. f_masonry();

  4. $("img").lazyload({

  5. effect:"fadeIn",

  6. failurelimit:40,

  7. load:f_masonry,

  8. });

  9. });

  10. function f_masonry() {

  11. $('.masonry').masonry({

  12. gutterWidth: 20,

  13. itemSelector: '.item',

  14. isAnimated: true,

  15. });

  16. }

  17. </script>

最后再吐槽一下网上各种不负责任复制粘贴来的文章,参考价值略低,甚至各种错误(自己动手丰衣足食)。

附件:Demo下载地址
https://github.com/jzj1993/masonry-lazyload-demos