作為一隻前端狗,我們的使命就是在滿足產品需求、實現互動設計的基礎上,將最好的體驗呈現給使用者爸爸們。在保證效能的同時,我們通常會給頁面加一些動態效果,以增強頁面的表現力並提升頁面的互動體驗。故將前端實現動效的幾種常用方式整理成此篇小結,以求溫故而知新,如有不當還望多多指正
童年.png
動畫即童年
動畫是指由許多幀靜止的畫面,以一定的速度(如每秒16張)連續播放時,肉眼因視覺殘象產生錯覺,而誤以為畫面活動的作品。– 維基百科
以上是維基百科上給出的動畫的定義。相信每一個像我這樣有童年的孩子,應該都玩過手翻書,或者就算你的童年稍微暗淡一點,應該也看過動畫片吧…嗯嗯,並沒有跑題,其實這和我們今天提及的動畫本質上是一樣的,只不過就是呈現方式或者說載體發生了改變。
幾個基本概念
簡單介紹幾個關於動畫的基本概念:
幀:在動畫過程中,每一幅靜止畫面即為一“幀”;
幀率:即每秒鐘播放的靜止畫面的數量,單位是fps(Frame per second)或赫茲(Hz);
幀時長:即每一幅靜止畫面的停留時間,單位一般是ms(毫秒);
丟幀:在幀率固定的動畫中,某一幀的時長遠高於平均幀時長,導致其後續數幀被擠壓而丟失的現象;
我們在顯示器上看到的動畫,每一幀變化都是系統繪製出來的(GPU或者CPU)。它的最高繪製頻率受限於顯示器的重新整理頻率(而非顯示卡,大多數是60Hz或者75Hz)。
幀頻越高,螢幕上圖片閃爍感就越小,穩定性也就越高。人的眼睛不容易察覺75Hz以上重新整理頻率帶來的閃爍感。
實現方式
通常我們在前端實現動畫效果的幾種主要實現方式如下:
- JavaScript:通過定時器(setTimeout 和 setIterval)來間隔來改變元素樣式,或者使用requestAnimationFrame;
- CSS3:transition 和 animation;
- HTML5:使用HTML5提供的繪圖方式(canvas、svg、webgl);
requestAnimationFrame
requestAnimationFrame
是瀏覽器用於定時迴圈操作的一個介面,類似於setTimeout
,主要用途是按幀對網頁進行重繪。
設定這個API的目的是為了讓各種網頁動畫效果(DOM動畫、Canvas動畫、SVG動畫、WebGL動畫)能夠有一個統一的重新整理機制,從而節省系統資源,提高系統效能,改善視覺效果。程式碼中使用這個API,就是告訴瀏覽器希望執行一個動畫,讓瀏覽器在下一個動畫幀安排一次網頁重繪。
requestAnimationFrame
使用一個回撥函式作為引數,這個回撥函式會在瀏覽器重繪之前呼叫,由於功效只是一次性的,所以想實現連續的動效,需要遞迴呼叫,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div id="demo" style="position:absolute; width:100px; height:100px; background:#ccc; left:0; top:0;"></div> <script> var demo = document.getElementById('demo'); function render(){ demo.style.left = parseInt(demo.style.left) + 1 + 'px'; //每一幀向右移動1px } requestAnimationFrame(function(){ render(); //當超過300px後才停止 if(parseInt(demo.style.left) <= 300) requestAnimationFrame(arguments.callee); }); </script> |
cancelAnimationFrame方法用於取消重繪:
1 2 |
var requestID = requestAnimationFrame(repeatOften); cancelAnimationFrame(requestID); |
使用requestAnimationFrame
API的優勢如下:
- 會把每一幀中的所有DOM操作集中起來,在一次重繪或迴流中就完成,並且重繪或迴流的時間間隔緊緊跟隨顯示器的重新整理頻率(60 Hz或者75 Hz);
- 在隱藏或不可見的元素中,將不會進行重繪或迴流,這當然就意味著更少的的cpu,gpu和記憶體使用量;
目前,主要瀏覽器Firefox 23 / IE 10 / Chrome / Safari)都支援這個方法。可以用下面的方法,檢查瀏覽器是否支援這個API。如果不支援,則自行模擬部署該方法。
1 2 3 4 5 6 7 8 9 10 |
window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element){ window.setTimeout(callback, 1000 / 60); }; })(); |
所以,可以這麼說,requestAnimationFrame
就是一個效能優化版、專為動畫量身打造的setTimeout
,不同的是requestAnimationFrame
不是自己指定回撥函式執行的時間,而是跟著瀏覽器內建的重新整理頻率來執行回撥,這當然就能達到瀏覽器所能實現動畫的最佳效果了。
Transition
CSS 中的 transition 屬性允許塊級元素中的屬性在指定的時間內平滑的改變,簡單看下其語法規則:
1 |
transition: property duration timing-function delay; |
具體屬性值介紹如下:
值 | 描述 |
---|---|
transition-property | 規定設定過渡效果的 CSS 屬性的名稱。(none / all / property) |
transition-duration | 規定完成過渡效果需要多少秒或毫秒。 |
transition-timing-function | 規定速度效果的速度曲線。(linear、ease、ease-in、ease-out、ease-in-out、cubic-bezier(n,n,n,n)) |
transition-delay | 定義過渡效果何時開始。 |
Animation
類似的CSS還提供了一個Animation屬性,不過區別於Transition,Animation作用於元素本身而不是樣式屬性,可以使用關鍵幀的概念,應該說可以實現更自由的動畫效果。
語法
1 |
animation: name duration timing-function delay iteration-count direction; |
具體屬性值介紹如下:
值 | 描述 |
---|---|
animation-name | 規定需要繫結到選擇器的 keyframe 名稱。(keyframename、none) |
animation-duration | 規定完成動畫所花費的時間,以秒或毫秒計。 |
animation-timing-function | 規定動畫的速度曲線。(linear、ease、ease-in、ease-out、ease-in-out、cubic-bezier(n,n,n,n)) |
animation-delay | 規定在動畫開始之前的延遲。 |
animation-iteration-count | 規定動畫應該播放的次數。 |
animation-direction | 規定是否應該輪流反向播放動畫。 (normal、alternate) |
Canvas
是HTML5新增的元素,作為頁面圖形繪製的容器,可用於通過使用JavaScript中的指令碼來繪製圖形。例如,它可以用於繪製圖形,製作照片,建立動畫,甚至可以進行實時視訊處理或渲染,Canvas具有如下特點:
- 依賴解析度,基於點陣圖;
- 不支援事件處理器;
- 弱的文字渲染能力;
- 能夠以 .png 或 .jpg 格式儲存結果影象;
- 最適合影象密集型的遊戲,其中的許多物件會被頻繁重繪;
大多數 Canvas 繪圖 API 都沒有定義在
SVG
SVG是英文Scalable Vector Graphics的縮寫,意為可縮放向量圖形,用來定義用於網路的基於向量的圖形,其使用 XML 格式定義影象,並且具有如下特點:
- 不依賴解析度,基於向量圖;
- 支援事件處理器;
- 最適合帶有大型渲染區域的應用程式(比如谷歌地圖);
- 複雜度高會減慢渲染速度(任何過度使用 DOM 的應用都不快);
- 不適合遊戲應用;
來看一個簡單的示例,用SVG畫了一個圓:
1 2 3 4 |
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <rect x="50" y="20" rx="20" ry="20" width="150" height="150" style="fill:red;stroke:black;stroke-width:5;opacity:0.5"/> </svg> |
SVG 程式碼以 元素開始,包括開啟標籤 和關閉標籤 。這是根元素。width 和 height 屬性可設定此 SVG 文件的寬度和高度。version 屬性可定義所使用的 SVG 版本,xmlns 屬性可定義 SVG 名稱空間。
SVG 的 用來建立一個圓。cx 和 cy 屬性定義圓中心的 x 和 y 座標。如果忽略這兩個屬性,那麼圓點會被設定為 (0, 0)。r屬性定義圓的半徑。
下面主要是介紹SVG中的幾個用於動畫的元素,它們分別是:
:通常放置到一個SVG影象元素裡面,用來定義這個影象元素的某個屬性的動畫變化過程;
:元素也是放置一個影象元素裡面,它可以引用一個事先定義好的動畫路徑,讓影象元素按路徑定義的方式運動;
:元素對圖形的運動和變換有更多的控制,它可以指定圖形的變換、縮放、旋轉和扭曲等;
:元素的用法在上面的例子裡出現過,它是一個輔助元素,通過它,等元素可以引用一個外部的定義的。讓影象元素按這個軌跡運動;
WebGL
WebGL使得網頁在支援HTML 標籤的瀏覽器中,不需要安裝任何外掛,便可以使用基於 OpenGL ES 2.0 的 API 在 canvas 中進行3D渲染。 WebGL 程式由JavaScript的控制程式碼,和在計算機的圖形處理單元(GPU)中執行的特效程式碼(shader code,渲染程式碼) 組成。
WebGL 本質上是基於光柵化的 API,而不是基於 3D 的 API。WebGL 只關注兩個方面,即投影矩陣的座標和投影矩陣的顏色。使用 WebGL 程式的任務就是實現具有投影矩陣座標和顏色的 WebGL 物件即可。可以使用“著色器”來完成上述任務。頂點著色器可以提供投影矩陣的座標,片段著色器可以提供投影矩陣的顏色。
由於WebGL的體系比較龐大,三言兩語說不完,所以以下僅提供各種傳送門了(不許說我懶!!):
WebGL 參考資料
WebGL API
幾個常用的動畫庫
Ani.js — 基於CSS動畫的生命處理庫
Dynamics.js — 建立具有物理運動效果動畫的js庫
Animate.css — 齊全的CSS3動畫庫
Three.js — 讓使用者通過javascript入手進入搭建webgl專案的類庫