揭祕騰訊burberry活動頁面中的特效

4月24日,Burberry亞太地區規模最大的旗艦店在上海開幕。Burberry突破性地運用了諸多創新的數字營銷模式,藉助與騰訊的合作,爲更多未能到場的用戶創造了一個“平行的體驗”,也正式開啓了Burberry的創新數字營銷之旅。

騰訊的營銷頁面: 最終效果

其中多次用到了類似於雲霧褪去的效果,如下圖。
最終效果
我對這種神奇的特效產生的極大的興趣,於是通過chrome的審查元素裏面Resources找到下面這張圖片(由於圖片是白色的png,爲了讓大家看清楚我將背景調成了黑色)。
最終效果
於是效果的實現方式就顯而易見了,是利用css3的-webkit-mask來實現的。

####Step1.爲背景加上蒙板  


<body>
    <div class="stage">
        <div class="sprite1"></div>
    </div>
</body>
.stage{
    width: 320px;
    height: 480px;
    position: absolute;
    left: 50%;
    top: 50%;
    margin-top:-240px;
    margin-left:-160px;
    background: url('./img/bg.jpg') no-repeat;
    background-size: auto 100%;
}
.stage .sprite1{
    width: 100%;
    height: 100%;
    background: url('./img/bg2.jpg') no-repeat;
    background-size: auto 100%;
    -webkit-mask:url('./img/Touch1.png') no-repeat;
    -webkit-mask-size: 100% 100%;
}


這裏爲了在桌面瀏覽器中觀看方便,將畫面大小調整成了320*480並居中。在sprite1中添加background的同時也增加了蒙板。


-webkit-mask:url('./img/Touch1.png') no-repeat;
-webkit-mask-size: 100% 100%;

我們這裏將蒙板的大小設置爲100%來觀察蒙板的效果。圖中畫圈圈的地方就是sprite1透過蒙板展示出來的部分。
最終效果
我們看到這個蒙板Touch1.png應該是一個序列幀組成的圖片,我們只需要將其一幀幀的顯示出來就可以實現動畫了。
點擊查看歷史代碼

Step2.序列幀動畫

.stage .sprite1{
    ......
    -webkit-mask-size: 400% 300%;
    -webkit-mask-position: 0% 0%;
}


Touch1.png是序列幀的整合圖片,其中一排有4幀一共有3排,所以我們將-webkit-mask-size設爲400% 300%。將-webkit-mask-postion設爲0% 0%表示從第一幀開始。做動畫時只需要依次修改-webkit-mask-position的x與y值,每次將x增加25%(100/每排的幀數4)直到75%,y增加33.33%(100/每牌的幀數3)直到66.66%。我們需要將每一幀的position狀態在不同的時間賦給sprite1,這只需要用setTimeout就可以了。

我們新建一個spriteClip類,並傳入(dom,w,h,time)四個參數,其中dom用來定位sprite1這個元素,w爲一排有幾幀,h爲一共有幾行,time爲每一幀之間的間隔。


function spriteClip(dom,w,h,time){
    if(dom){
        this.dom = dom;
        this.w = w ||0;
        this.h = h ||0;
        this.time = time || 0;
    }else{
        return false;
    }
}



新建run方法。遍歷w與h算出時間與位置,用setTimeout設置好延時執行


spriteClip.prototype.run = function(){
    for(var w=0;w<this.w;w++){
        for(var h =0;h<this.h;h++){
            //這裏使用閉包以免w,h值隨循環改變。
            (function(w,h,self){
                //計算時間
                var time = (h*self.time*self.w+w*self.time);
                setTimeout(function(){
                    //計算位置
                    self.dom.style.webkitMaskPosition = (100/(self.w-1))*w+'% '+(100/(self.h-1))*h+'%';
                },time);
            })(w,h,this);
        }
    }
}




新建並運行spriteClip。


var sprite1 = document.querySelector('.sprite1');
var sp1 = new spriteClip(sprite1,4,3,50);
sp1.run();




運行代碼:
最終效果
點擊查看歷史代碼

Step3.添加動畫控制

有了sprite1後,再添加3個sprite,將所有的動畫按照順序播放來形成完整的轉場。爲了實現按照順序的播放,我們需要爲動畫添加播放控制。即在播放動畫完成後給dom觸發一個finish事件,dom接到完成事件後執行下一個動畫。同時添加showhide用來控制動畫的顯示/隱藏。


function spriteClip(dom,w,h,time){
    if(dom){
        ......
        //記錄dom初始的display狀態
        this.display = this.dom.style.display;
        //記錄動畫是否播放過
        this.played = false;
    }else{
        return false;
    }
}
spriteClip.prototype.run = function(){
    //如果動畫已經播放過則不做任何動畫
    if(this.played)
        return false;
    //標記爲已播放完成
    this.played = true;
    //讓dom顯示
    this.show();
    for(var w=0;w<this.w;w++){
        for(var h =0;h<this.h;h++){
            (function(w,h,self){
                var time = (h*self.time*self.w+w*self.time);
                setTimeout(function(){
                    ......
                    if(w >= self.w-1 && h>=self.h-1){
                        //動畫結束
                        var event = document.createEvent('HTMLEvents');
                        event.initEvent('finish', true, true);
                        event.eventType = 'message';
                        event.content =  'finish';
                        //觸發finish事件
                        self.dom.dispatchEvent(event);
                    }
                },time);
            })(w,h,this);
        }
    }
}
//隱藏dom
spriteClip.prototype.hide = function(){
    this.dom.style.display = 'none';
}
//顯示dom
spriteClip.prototype.show = function(){
    this.dom.style.display = this.display;
}
//接收finish時間並用callback函數處理
spriteClip.prototype.finish = function(callback){
    this.dom.addEventListener('finish',callback);
}
var sprite1 = document.querySelector('.sprite1');
var sp1 = new spriteClip(sprite1,4,3,50);
//在做動畫之前讓sprite隱藏
sp1.hide();
document.addEventListener('touchend',function(){
    //手指擡起後運行動畫
    sp1.run();
});
document.addEventListener('click',function(){
    //點擊後運行動畫
    sp1.run();
});
sp1.finish(function(){
    //動畫完成
    console.log('finish');
});




下面添加剩下的3個sprite。


......
.stage .sprite2{
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0px;
    top: 0px;
    background: url('./img/bg2.jpg') no-repeat;
    background-size: auto 100%;
    -webkit-mask:url('./img/Touch2.png') no-repeat;
    -webkit-mask-size: 400% 300%;
    -webkit-mask-position: 0% 0%;
}
.stage .sprite3{
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0px;
    top: 0px;
    background: url('./img/bg2.jpg') no-repeat;
    background-size: auto 100%;
    -webkit-mask:url('./img/Touch3.png') no-repeat;
    -webkit-mask-size: 400% 300%;
    -webkit-mask-position: 0% 0%;
}
.stage .sprite4{
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0px;
    top: 0px;
    background: url('./img/bg2.jpg') no-repeat;
    background-size: auto 100%;
    -webkit-mask:url('./img/Touch4.png') no-repeat;
    /* Touch4是4*5 */
    -webkit-mask-size: 400% 500%;
    -webkit-mask-position: 0% 0%;
}
......
<div class="stage">
    <div class="sprite1"></div>
    <div class="sprite2"></div>
    <div class="sprite3"></div>
    <div class="sprite4"></div>
</div>
.....
//新建4個sprite
var sprite1 = document.querySelector('.sprite1');
var sprite2 = document.querySelector('.sprite2');
var sprite3 = document.querySelector('.sprite3');
var sprite4 = document.querySelector('.sprite4');
var sp1 = new spriteClip(sprite1,4,3,80);
var sp2 = new spriteClip(sprite2,4,3,80);
var sp3 = new spriteClip(sprite3,4,3,80);
var sp4 = new spriteClip(sprite4,4,5,80);
sp1.hide();
sp2.hide();
sp3.hide();
sp4.hide();
document.addEventListener('touchend',function(){
    sp1.run();
});
document.addEventListener('click',function(){
    sp1.run();
});
sp1.finish(function(){
    //sprite1結束後運行sprite2
    sp2.run();
});
sp2.finish(function(){
    //sprite2結束後運行sprite3
    sp3.run();
});
sp3.finish(function(){
    //sprite3結束後運行sprite4
    sp4.run();
})
......




運行代碼:

最終效果




查看所有代碼請去Github

如有問題或者建議請微博@UED天機。我會及時回覆,也可以提供其他特效一起討論其實現方法。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章