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接到完成事件後執行下一個動畫。同時添加show
和hide
用來控制動畫的顯示/隱藏。
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(); }) ......
運行代碼:
如有問題或者建議請微博@UED天機。我會及時回覆,也可以提供其他特效一起討論其實現方法。