瀑布流

Design Samsung 效果瀑布流插件

阿里云

本教程将教大家怎么样实现“Design Samsung”网站上的瀑布流效果。这个效果是先有一个彩色的背景滑出,然后图片再在其上滑出,当向下滚动时,不断有图片被加载的瀑布流效果。如果你曾今访问过 Design Samsung 网站,那么你一定已经见识过这种神奇的效果了。彩色的背景先从左边滑出,随后图片再在其上左边从滑出,彩色的背景代表了图片的主要色彩(某张图片的主导颜色)。这是一个非常有创意的图片懒加载效果,本教程将教你如何使用 Masonry 和 CSS animations 来实现这种效果。

HTML 结构:

我们使用一个 section 来做 wrapper,然后在里面放一个无序列表,给第一个 li 元素添加 class 为 title-box

也想出现在这里?联系我们
创客主机
  1. <section class="grid-wrap">
  2.     <ul class="grid swipe-right" id="grid">
  3.         <li class="title-box">
  4.             <h2>Illustrations by <a href="http://ryotakemasa.com/">Ryo Takemasa</a></h2>
  5.         </li>
  6.         <li><a href="#"><img src="img/1.jpg" alt="img01"><h3>Kenpo News April 2014 issue</h3></a></li>
  7.         <li><a href="#"><img src="img/2.jpg" alt="img02"><h3>SQUET April 2014 issue</h3></a></li>
  8.         <li><!-- ... --></li>
  9.         <!-- ... -->
  10.     </ul>
  11. </section>

每一个 li 元素都包含一张图片和一个标题。注意:我们将使用 swipe-right、swipe-down 和 swipe-rotate 中的一个样式来控制无序列表的运动。当页面加载后,我们希望那些可视区域内的图片已经被加载,然后当我们滚动鼠标的时候,希望图片能以懒加载的形式被加载。这些将靠 animate 属性来实现。最开始可视区域的元素我们给定 shown 样式,这样,它们将不会懒加载。彩色的背景需要添加动态效果,我们在标题之后添加一个 div,并在其中加入一个 a 标签,给这个 div 添加 classcurtain,然后使用 ColorFinder.js 将它的背景色设置为图片的主导色。

CSS 样式:

首先,我们需要设置 wrapper 的最大宽度,设置为 1260px(这样方便我们在每一行中添加 4 张图片)

  1. .grid-wrap {
  2.     clear: both;
  3.     margin: 0 auto;
  4.     padding: 0;
  5.     max-width: 1260px;
  6. }

无序列表要居中放置,并去掉它的原始样式。

  1. .grid {
  2.     margin: 30px auto;
  3.     padding: 0;
  4.     min-height: 500px;
  5.     list-style: none;
  6. }

我们希望用 javascript 来控制 Loadding 图片是否可见,我们使用 loaded 来控制它,当图片加载完成后,添加 loaded 样式。

  1. .js .grid {
  2.     background: url(../img/loading.gif) no-repeat 50% 100px;
  3. }
  4.  
  5. .js .grid.loaded {
  6.     background: none;
  7. }

这样做的目的的在图片加载完成之前不显示任何东西。每一个 li 都需要左浮动,宽设置为 314px(图片的宽度加上 a 元素的 margin)。

  1. .grid li {
  2.     display: inline-block;
  3.     overflow: hidden;
  4.     width: 314px;
  5.     text-align: left;
  6.     vertical-align: top;
  7. }
  8.  
  9. .js .grid li {
  10.     display: none;
  11.     float: left;
  12. }
  13.  
  14. .js .grid.loaded li {
  15.     display: block;
  16. }

接下来给标题添加一些样式:

  1. .title-box h2 {
  2.     display: block;
  3.     margin: 7px;
  4.     padding: 20px;
  5.     background: #2E3444;
  6.     color: #D3EEE2;
  7.     text-transform: uppercase;
  8.     letter-spacing: 1px;
  9.     font-weight: 300;
  10. }
  11.  
  12. .title-box h2 a {
  13.     display: block;
  14.     font-weight: 900;
  15. }
  16.  
  17. .title-box h2 a:hover {
  18.     color: #D3EEE2;
  19. }

为 a 元素和图片添加样式:

  1. .grid li > a,
  2. .grid li img {
  3.     display: block;
  4.     outline: none;
  5.     border: none;
  6. }

为了不让彩色的背景超出界限,需要给 a 元素添加 overflow:hidden

  1. .grid li > a {
  2.     position: relative;
  3.     overflow: hidden;
  4.     margin: 7px;
  5. }

curtain 需要绝对定位,并设置为 100%宽和 100%高。

  1. .grid .curtain {
  2.     position: absolute;
  3.     top: 0;
  4.     left: 0;
  5.     width: 100%;
  6.     height: 100%;
  7.     background: #96cdc8;
  8. }

为了使效果正常,curtain 必须在图片和标题之上。我们要做的三种效果分别使 curtain 从左边、上边和从左边旋转展开。

  1. .grid.swipe-right .curtain {
  2.     transform: translate3d(-100%,0,0);
  3. }
  4.  
  5. .grid.swipe-down .curtain {
  6.     transform: translate3d(0,-100%,0);
  7. }
  8.  
  9. .grid.swipe-rotate .curtain {
  10.     width: 200%;
  11.     height: 200%;
  12.     transform: rotate3d(0,0,1,90deg);
  13.     transform-origin: top left;
  14. }

另外,我们在 curtain 上使用伪元素为图片添加一些阴影效果。

  1. .grid .curtain::after {
  2.     position: absolute;
  3.     top: 0;
  4.     left: 0;
  5.     width: 100%;
  6.     height: 100%;
  7.     background: rgba(0,0,0,1);
  8.     content: '';
  9. }
  10.  
  11. .grid.swipe-right .curtain::after,
  12. .grid.swipe-rotate .curtain::after {
  13.     left: -100%;
  14. }
  15.  
  16. .grid.swipe-down .curtain::after {
  17.     top: -100%;
  18. }

给标题添加一个较深的背景色,并使它绝对定位。

  1. .grid li h3 {
  2.     position: absolute;
  3.     bottom: 0;
  4.     left: 0;
  5.     margin: 0;
  6.     padding: 20px;
  7.     width: 100%;
  8.     background: #2E3444;
  9.     color: #D3EEE2;
  10.     text-align: right;
  11.     text-transform: uppercase;
  12.     letter-spacing: 1px;
  13.     font-weight: 800;
  14.     font-size: 1em;
  15.     transition: transform 0.2s, color 0.2s;
  16. }

我们使用 a 元素的::before 伪元素来做鼠标划过图片的效果。把它设置为绝对定位,当鼠标划过时,边框将产生运动效果。标题将向上移动一些,并且颜色会有所变化。

  1. .grid li > a::before {
  2.     position: absolute;
  3.     top: 0;
  4.     left: 0;
  5.     width: 100%;
  6.     height: 100.5%; 
  7.     border: 0px solid transparent;
  8.     background: transparent;
  9.     content: '';
  10.     transition: border-width 0.2s, border-color 0.2s;
  11. }
  12.  
  13. /* Hover effects */
  14. .grid li.shown:hover h3 {
  15.     color: #fff;
  16.     transform: translate3d(0,-30px,0);
  17. }
  18.  
  19. .grid li.shown:hover > a::before {
  20.     border-width: 14px;
  21.     border-color: #2E3444;
  22. }

现在,让我们来制作运动效果。前面已经提到过,我们给 curtain 定义了一个“hidden”状态,现在可以加以运用了。当我们滚动页面时,我们将给它添加 class animate 来触发运动。为了达到正确的效果,我们先让 curtain translate 到 0,使它从左边运动到中间,然后在使它 translate 到右边。通过设置 translate 从 0 到 50%再到 60%,来确保它每次只增长一点,而不是一下就从左边增长到右边。

  1. /* Swipe right */
  2. .grid.swipe-right li.animate .curtain {
  3.     animation: swipeRight 1.5s cubic-bezier(0.6,0,0.4,1) forwards;
  4. }
  5.  
  6. @keyframes swipeRight {
  7.     50%, 60% { transform: translate(0); }
  8.     100% { transform: translate3d(100%,0,0); }
  9. }

(为什么这里需要 translate(0)?因为某些浏览器,比如 IE11 貌似在这个例子中使用 translate3d(0,0,0)会有些问题。)向下运动的效果类似,我们需要调整的是 Y 轴而不是 X 轴。

  1. /* Swipe down */
  2. .grid.swipe-down li.animate .curtain {
  3.     animation: swipeDown 1.5s cubic-bezier(0.6,0,0.4,1) forwards;
  4. }
  5.  
  6. @keyframes swipeDown {
  7.     50%, 60% { transform: translate(0); }
  8.     100% { transform: translate3d(0,-100%,0); }
  9. }

同样,旋转效果我们只需要 rotate 它既可。

  1. /* Swipe rotate */
  2. .grid.swipe-rotate li.animate .curtain {
  3.     animation: swipeRotate 1.5s ease forwards;
  4. }
  5.  
  6. @keyframes swipeRotate {
  7.     50%, 60% { transform: rotate3d(0,0,1,0deg); }
  8.     100% { transform: rotate3d(0,0,1,-90deg); }
  9. }

阴影的淡入淡出效果只是简单的改变 curtain 的伪元素的透明度。

  1. .grid li.animate .curtain::after {
  2.     animation: fadeOut 1.5s ease forwards;
  3.     animation-delay: inherit;
  4. }
  5.  
  6. @keyframes fadeOut {
  7.     50%, 60% { opacity: 1; }
  8.     100% { opacity: 0; }
  9. }

当我们使用 js 来控制运动的间隔时间时,需要确保伪元素和它的父元素的值相同。这里我们设置 animation-delay 为 inherit。最后,我们需要隐藏图片和标题,直到它运动到 60%时才显示出来。通过使用 step-end(它等效于 steps(1, end)),我们能够正确的控制时间。

  1. .js .grid li img,
  2. .js .grid li h3 {
  3.     visibility: hidden;
  4. }
  5.  
  6. .grid li.animate img,
  7. .grid li.animate h3 {
  8.     animation: showMe 1.5s step-end forwards;
  9. }
  10.  
  11. @keyframes showMe {
  12.     from { visibility: hidden; }
  13.     60%, 100% { visibility: visible; }
  14. }
  15.  
  16. .grid li.shown img,
  17. .grid li.shown h3 {
  18.     visibility: visible;
  19. }

Javascript 部分:

当我们滚动鼠标时,我们需要做什么呢?我们需要一种懒加载的效果,最开始出现的图片我们不希望它们有动画效果,我们还需要获取图片的主导色来填充背景。现在开始写 js 代码。minDelay 和 maxDelay 用来定义动画的延迟时间的范围。这将使每张图片的动画时间略有不同,从而是整体效果更佳。如果你想使图片在同一时间开始运动,可以将 maxDelay 调整为 0。viewportFactor 定义了有多少将被触发动画的图片出现。0(0%)表示当图片显示在屏幕中的时候就触发动画,1(100%)表示图片在屏幕中加载完毕才触发动画。

  1. GridScrollFx.prototype.options = {
  2.     minDelay : 0,
  3.     maxDelay : 500,
  4.     viewportFactor : 0
  5. }

现在来初始化一些参数,同时初始化 Masonry。为了使 Masonry 能够正常工作,我们需要预加载图片。接着我们需要区分屏幕上的图片那些是已经加载好的,已经加载好的图片我们需要添加上 class shown 使它们可见。对那些不在屏幕中的图片,我们要添加 curtain,这样当它们滚动到屏幕显示区域时,将产生动画效果。我们还要为所有的图片添加动画延迟。最后,我们为 window 绑定 scroll 和 resize 事件。具体代码如下:

  1. GridScrollFx.prototype._init = function() {
  2.     var self = this, items = [];
  3.  
  4.     [].slice.call( this.el.children ).forEach( function( el, i ) {
  5.         var item = new GridItem( el );
  6.         items.push( item );
  7.     } );
  8.  
  9.     this.items = items;
  10.     this.itemsCount = this.items.length;
  11.     this.itemsRenderedCount = 0;
  12.     this.didScroll = false;
  13.  
  14.     imagesLoaded( this.el, function() {
  15.         // show grid
  16.         self.el.style.display = 'block';
  17.  
  18.         // initialize masonry
  19.         new Masonry( self.el, {
  20.             itemSelector : 'li',
  21.             isFitWidth : true,
  22.             transitionDuration : 0
  23.         } );
  24.  
  25.         // the items already shown...
  26.         self.items.forEach( function( item ) {
  27.             if( inViewport( item.el ) ) {
  28.                 ++self.itemsRenderedCount;
  29.                 classie.add( item.el, 'shown' );
  30.             }
  31.             else {
  32.                 item.addCurtain();
  33.                 // add random delay
  34.                 item.changeAnimationDelay( Math.random() * ( self.options.maxDelay - self.options.minDelay ) + self.options.minDelay );
  35.             }
  36.         } );
  37.  
  38.         var onScrollFn = function() {
  39.             if( !self.didScroll ) {
  40.                 self.didScroll = true;
  41.                 setTimeout( function() { self._scrollPage(); }, 200 );
  42.             }
  43.  
  44.             if( self.itemsRenderedCount === self.itemsCount ) {
  45.                 window.removeEventListener( 'scroll', onScrollFn, false );
  46.             }
  47.         }
  48.  
  49.         // animate the items inside the viewport (on scroll)
  50.         window.addEventListener( 'scroll', onScrollFn, false );
  51.         // check if new items are in the viewport after a resize
  52.         window.addEventListener( 'resize', function() { self._resizeHandler(); }, false );
  53.     });
  54. }

注意我们创建了一个函数 GridItem 来控制每一张图片的数据和方法。当 curtain 元素被创建,我们设置它的背景色,背景色将被设置为图片的主导色,这可以通过 Colorfinder 插件来实现。

  1. function GridItem( el ) {
  2.     this.el = el;
  3.     this.anchor = el.querySelector( 'a' ) 
  4.     this.image = el.querySelector( 'img' );
  5.     this.desc = el.querySelector( 'h3' );
  6. }
  7.  
  8. GridItem.prototype.addCurtain = function() {
  9.     if( !this.image ) return;
  10.     this.curtain = document.createElement( 'div' );
  11.     this.curtain.className = 'curtain';
  12.     var rgb = new ColorFinder( function favorHue(r,g,b) {
  13.         // exclude white
  14.         //if (r>245 && g>245 && b>245) return 0;
  15.         return (Math.abs(r-g)*Math.abs(r-g) + Math.abs(r-b)*Math.abs(r-b) + Math.abs(g-b)*Math.abs(g-b))/65535*50+1;
  16.     } ).getMostProminentColor( this.image );
  17.     if( rgb.r && rgb.g && rgb.b ) {
  18.         this.curtain.style.background = 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')';
  19.     }
  20.     this.anchor.appendChild( this.curtain );
  21. }
  22.  
  23. GridItem.prototype.changeAnimationDelay = function( time ) {
  24.     if( this.curtain ) {
  25.         this.curtain.style.WebkitAnimationDelay = time + 'ms';
  26.         this.curtain.style.animationDelay = time + 'ms';
  27.     }
  28.     if( this.image ) {
  29.         this.image.style.WebkitAnimationDelay = time + 'ms';
  30.         this.image.style.animationDelay = time + 'ms';
  31.     }
  32.     if( this.desc ) {
  33.         this.desc.style.WebkitAnimationDelay = time + 'ms';
  34.         this.desc.style.animationDelay = time + 'ms';
  35.     }
  36. }

现在让我们来看看滚动鼠标时会发生什么。首先,程序迭代所有的图片,看看那些已经在屏幕中出现,那些还没有出现。如果一张图片没有 curtain,那么就添加一个 class shown 并返回。否则就添加 class animate 来触发动画。当动画结束,就添加 class shown 并去掉 class animate。

  1. GridScrollFx.prototype._scrollPage = function() {
  2.     var self = this;
  3.     this.items.forEach( function( item ) {
  4.         if( !classie.has( item.el, 'shown' ) && !classie.has( item.el, 'animate' ) && inViewport( item.el, self.options.viewportFactor ) ) {
  5.             ++self.itemsRenderedCount;
  6.  
  7.             if( !item.curtain ) {
  8.                 classie.add( item.el, 'shown' );
  9.                 return;
  10.             };
  11.  
  12.             classie.add( item.el, 'animate' );
  13.  
  14.             // after animation ends add class shown
  15.             var onEndAnimationFn = function( ev ) {
  16.                 if( support.animations ) {
  17.                     this.removeEventListener( animEndEventName, onEndAnimationFn );
  18.                 }
  19.                 classie.remove( item.el, 'animate' );
  20.                 classie.add( item.el, 'shown' );
  21.             };
  22.  
  23.             if( support.animations ) {
  24.                 item.curtain.addEventListener( animEndEventName, onEndAnimationFn );
  25.             }
  26.             else {
  27.                 onEndAnimationFn();
  28.             }
  29.         }
  30.     });
  31.     this.didScroll = false;
  32. }

当调整了显示窗口的大小,我们需要检查图片是否在可视区域。

  1. GridScrollFx.prototype._resizeHandler = function() {
  2.     var self = this;
  3.     function delayed() {
  4.         self._scrollPage();
  5.         self.resizeTimeout = null;
  6.     }
  7.     if ( this.resizeTimeout ) {
  8.         clearTimeout( this.resizeTimeout );
  9.     }
  10.     this.resizeTimeout = setTimeout( delayed, 1000 );
  11. }

Design Samsung 效果瀑布流插件

已有 389 人购买
查看演示升级 VIP立刻购买

演示地址 下载地址
收藏
(0)

发表回复

热销模板

Ashade - 作品展示摄影相册WordPress汉化主题
LensNews

本站承接 WordPress / PbootCMS / DedeCMS 等
系统建站、仿站、开发、定制等业务!