天天看點

巧用 mask-image 實作簡單進度加載界面

最近給 nzoo 折騰官網,拿 angular2.0 + webpack 實作SPA,然後覺得最終打包後的出口檔案有點大,使用者首次通路會有一個時間較長的白屏等候界面,感覺體驗不太好。

于是希望在使用者下載下傳整個 bundle 時能夠先看到一個“加載中”的UI做過度,鑒于 nzoo 的LOGO也較簡潔,便舍棄笨重的雪碧圖+step動畫的形式,轉以 mask-image + transition動畫來實作。

整體最終互動如下(模拟的是 2G 網速):

巧用 mask-image 實作簡單進度加載界面

雖然界面簡單,但整個動畫僅僅使用了一張3.5kb大小的圖檔(戳我檢視,注意是全白的會跟背景混一體):

巧用 mask-image 實作簡單進度加載界面

如互動截圖所示,我們希望在使用者剛進入頁面時,開始從底部給 logo 填色,持續10秒的 easeout 動畫然後停在距離頂部還有一小部分未填色的地方。

接着在使用者下載下傳完 bundle 後,用 300ms 時間填完整個logo再執行 angular 應用啟動腳本。

巧用 mask-image 實作簡單進度加載界面

什麼是 mask-image

擅長搗弄 Flash 甚至 AE 的朋友相信對“遮罩層”的概念會很清楚,都是指定某層的元件的輪廓/alpha通道來作為自己剪影的依據。在 Flash 中遮罩層隻支援矢量,而AE則支援多種形式的遮罩(畢竟人家用來後期的嘛)。

另外FW和PS都支援alpha遮罩(PS中稱為“蒙版”)。而今天要聊的css3中的 mask-image 則是以指定圖檔的透明度作為剪影依據的。

介個怎麼了解呢?我們來張簡單的示意圖:

巧用 mask-image 實作簡單進度加載界面

相信玩 flash 的童鞋會不屑地一笑,覺得是個好簡單的事兒—— 底部搞個填滿色的DOM由下往上運動,頂部固定放個輪廓層(png)剪影整個動畫就行了嘛。

然而現實比較骨感—— mask-image 所指定的遮罩圖會死死地固定在被遮罩元素上,可以了解為若元素動了那麼遮罩圖也會随着動。也就是說 flash 的那一套不适用于css3上。

此路不通換條道走—— 把動畫改為 transition + background-position 來實作,而不靠元素本身瞎運動了。

我們現在手頭有個 nzoo 的剪影,先看看填滿整個logo 顔色需要怎麼做,一共就倆步:

⑴ 放個DOM,給它配上 -webkit-mask-image 的樣式指定遮罩圖檔;

⑵ 給 DOM上漸變色(得多次微調讓漸變的角度、位置到位)。

于是初始化樣式是這樣的:

鑒于 firefox 還不支援在樣式中配置 mask-image 特性,是以代碼中我們沒寫 -moz-mask-image。(firefox的相容後面說)

總之與 mask-image 樣式結合前後的是醬子的:

巧用 mask-image 實作簡單進度加載界面

留意 nzoo 的字樣是有傾斜角度的,是以我們在 liner-gradient 中加了個 353deg 用于線性傾斜填充,這裡填充的角度以及位置,均是後期微調得出的資料。

接着我們在其頂部安放另一個DOM(<mask-top>),用作完全未填色的 logo (底色為#EEE):

為實作動畫再加上 background-position、background-size 和 transition 定義:

其中 background-size 的配置用于拉長線性填充的漸進線,并初始化 background-position 的垂直距離為 -50%(即剛好整個剪影區域都是有填滿#EEE的,剪影底部以下才則為rgba(0,0,0,0)的透明填充)。

是以後續我們通過動态改變 background-position 的垂直定位,把<mask-top>的漸進性由底部往上平移,進而逐漸展示出其下方的<mask-bg>元素的内容,就能實作整個加載動畫界面。

為了友善了解 <mask-top> 原理,我做了個效果圖:

巧用 mask-image 實作簡單進度加載界面

另外要留意的是我們給 transition 動畫加了個1秒延遲,主要是為了友善用戶端先下載下傳遮罩圖檔再執行動畫。

至于如何觸發 transition 就不廢話了,還是按老套數給父層元素動态加個 class 來實作:

注意這裡的 app 是我給 <mask-top> 和 <mask-top> 外部過了一層自定義DOM <app></app>,原本隻是用作後續挂載 angular 元件,現在咱把它用于存放挂載元件前先執行的加載互動元素。

在使用者下載下傳好 bundle 腳本之後(這時說明一切都loading好了),我們給 <app> 換上名為“loading-done”的類觸發“把logo全部填滿色”的 300ms 動畫,也順道延遲 300ms 再啟動angular:

于是在 webkit 浏覽器中一切就如同一開始的互動動畫一樣順利運作。

巧用 mask-image 實作簡單進度加載界面

Firefox 和 Edge

Firefox 與 chrome 不同,對 mask-image 有另一套标準,需要 svg 加持,我們看下示例:

巧用 mask-image 實作簡單進度加載界面

說白了就是往 svg 裡嵌入 XHTML 來實作,細心看看其實也不複雜。我們可以稍微改下代碼(主要是DOM結構)來做相容:

這樣在 Firefox 中也能正常運作我們的加載動畫了。

不過有趣的是,我在 caniuse 看到巨硬 Edge 是不支援 mask-image 的:

巧用 mask-image 實作簡單進度加載界面

而實際用上 Firefox 這套後發現居然能在 Edge 上順利運作了。

ok 大周末半夜三更的就跟大家唠嗑到這,想來我也許久沒寫樣式軟文了,共勉~

巧用 mask-image 實作簡單進度加載界面