前端動(dòng)畫大亂燉

作為一只前端狗,我們的使命就是在滿足產(chǎn)品需求、實(shí)現(xiàn)交互設(shè)計(jì)的基礎(chǔ)上,將最好的體驗(yàn)呈現(xiàn)給用戶爸爸們。在保證性能的同時(shí),我們通常會(huì)給頁(yè)面加一些動(dòng)態(tài)效果,以增強(qiáng)頁(yè)面的表現(xiàn)力并提升頁(yè)面的交互體驗(yàn)。故將前端實(shí)現(xiàn)動(dòng)效的幾種常用方式整理成此篇小結(jié),以求溫故而知新,如有不當(dāng)還望多多指正。

童年.png

動(dòng)畫即童年

動(dòng)畫是指由許多幀靜止的畫面,以一定的速度(如每秒16張)連續(xù)播放時(shí),肉眼因視覺(jué)殘象產(chǎn)生錯(cuò)覺(jué),而誤以為畫面活動(dòng)的作品。-- 維基百科

以上是維基百科上給出的動(dòng)畫的定義。相信每一個(gè)像我這樣有童年的孩子,應(yīng)該都玩過(guò)手翻書,或者就算你的童年稍微暗淡一點(diǎn),應(yīng)該也看過(guò)動(dòng)畫片吧...嗯嗯,并沒(méi)有跑題,其實(shí)這和我們今天提及的動(dòng)畫本質(zhì)上是一樣的,只不過(guò)就是呈現(xiàn)方式或者說(shuō)載體發(fā)生了改變。

超人大戰(zhàn)賽亞人.avi

幾個(gè)基本概念

簡(jiǎn)單介紹幾個(gè)關(guān)于動(dòng)畫的基本概念:

:在動(dòng)畫過(guò)程中,每一幅靜止畫面即為一“幀”;
幀率:即每秒鐘播放的靜止畫面的數(shù)量,單位是fps(Frame per second)或赫茲(Hz);
幀時(shí)長(zhǎng):即每一幅靜止畫面的停留時(shí)間,單位一般是ms(毫秒);
丟幀:在幀率固定的動(dòng)畫中,某一幀的時(shí)長(zhǎng)遠(yuǎn)高于平均幀時(shí)長(zhǎng),導(dǎo)致其后續(xù)數(shù)幀被擠壓而丟失的現(xiàn)象;

我們?cè)陲@示器上看到的動(dòng)畫,每一幀變化都是系統(tǒng)繪制出來(lái)的(GPU或者CPU)。它的最高繪制頻率受限于顯示器的刷新頻率(而非顯卡,大多數(shù)是60Hz或者75Hz)。

幀頻越高,屏幕上圖片閃爍感就越小,穩(wěn)定性也就越高。人的眼睛不容易察覺(jué)75Hz以上刷新頻率帶來(lái)的閃爍感。

實(shí)現(xiàn)方式

通常我們?cè)谇岸藢?shí)現(xiàn)動(dòng)畫效果的幾種主要實(shí)現(xiàn)方式如下:

  • JavaScript:通過(guò)定時(shí)器(setTimeout 和 setIterval)來(lái)間隔來(lái)改變?cè)貥邮剑蛘呤褂胷equestAnimationFrame;
  • CSS3:transition 和 animation;
  • HTML5:使用HTML5提供的繪圖方式(canvas、svg、webgl);
Animations.png

requestAnimationFrame

requestAnimationFrame是瀏覽器用于定時(shí)循環(huán)操作的一個(gè)接口,類似于setTimeout,主要用途是按幀對(duì)網(wǎng)頁(yè)進(jìn)行重繪。

設(shè)置這個(gè)API的目的是為了讓各種網(wǎng)頁(yè)動(dòng)畫效果(DOM動(dòng)畫、Canvas動(dòng)畫、SVG動(dòng)畫、WebGL動(dòng)畫)能夠有一個(gè)統(tǒng)一的刷新機(jī)制,從而節(jié)省系統(tǒng)資源,提高系統(tǒng)性能,改善視覺(jué)效果。代碼中使用這個(gè)API,就是告訴瀏覽器希望執(zhí)行一個(gè)動(dòng)畫,讓瀏覽器在下一個(gè)動(dòng)畫幀安排一次網(wǎng)頁(yè)重繪。

requestAnimationFrame使用一個(gè)回調(diào)函數(shù)作為參數(shù),這個(gè)回調(diào)函數(shù)會(huì)在瀏覽器重繪之前調(diào)用,由于功效只是一次性的,所以想實(shí)現(xiàn)連續(xù)的動(dòng)效,需要遞歸調(diào)用,示例如下:

<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'; //每一幀向右移動(dòng)1px
}
requestAnimationFrame(function(){
    render();
    //當(dāng)超過(guò)300px后才停止
    if(parseInt(demo.style.left) <= 300) requestAnimationFrame(arguments.callee);
});
</script>

cancelAnimationFrame方法用于取消重繪:

var requestID = requestAnimationFrame(repeatOften);
cancelAnimationFrame(requestID);

使用requestAnimationFrameAPI的優(yōu)勢(shì)如下:

  • 會(huì)把每一幀中的所有DOM操作集中起來(lái),在一次重繪或回流中就完成,并且重繪或回流的時(shí)間間隔緊緊跟隨顯示器的刷新頻率(60 Hz或者75 Hz);
  • 在隱藏或不可見的元素中,將不會(huì)進(jìn)行重繪或回流,這當(dāng)然就意味著更少的的cpu,gpu和內(nèi)存使用量;

目前,主要瀏覽器Firefox 23 / IE 10 / Chrome / Safari)都支持這個(gè)方法??梢杂孟旅娴姆椒ǎ瑱z查瀏覽器是否支持這個(gè)API。如果不支持,則自行模擬部署該方法。

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);
          };
})();

所以,可以這么說(shuō),requestAnimationFrame就是一個(gè)性能優(yōu)化版、專為動(dòng)畫量身打造的setTimeout,不同的是requestAnimationFrame不是自己指定回調(diào)函數(shù)運(yùn)行的時(shí)間,而是跟著瀏覽器內(nèi)建的刷新頻率來(lái)執(zhí)行回調(diào),這當(dāng)然就能達(dá)到瀏覽器所能實(shí)現(xiàn)動(dòng)畫的最佳效果了。

DEMO傳送門

Transition

CSS 中的 transition 屬性允許塊級(jí)元素中的屬性在指定的時(shí)間內(nèi)平滑的改變,簡(jiǎn)單看下其語(yǔ)法規(guī)則:

transition: property duration timing-function delay;

具體屬性值介紹如下:

描述
transition-property 規(guī)定設(shè)置過(guò)渡效果的 CSS 屬性的名稱。(none / all / property)
transition-duration 規(guī)定完成過(guò)渡效果需要多少秒或毫秒。
transition-timing-function 規(guī)定速度效果的速度曲線。(linear、ease、ease-in、ease-out、ease-in-out、cubic-bezier(n,n,n,n))
transition-delay 定義過(guò)渡效果何時(shí)開始。

DEMO傳送門

Animation

類似的CSS還提供了一個(gè)Animation屬性,不過(guò)區(qū)別于Transition,Animation作用于元素本身而不是樣式屬性,可以使用關(guān)鍵幀的概念,應(yīng)該說(shuō)可以實(shí)現(xiàn)更自由的動(dòng)畫效果。

語(yǔ)法

animation: name duration timing-function delay iteration-count direction;

具體屬性值介紹如下:

描述
animation-name 規(guī)定需要綁定到選擇器的 keyframe 名稱。(keyframename、none)
animation-duration 規(guī)定完成動(dòng)畫所花費(fèi)的時(shí)間,以秒或毫秒計(jì)。
animation-timing-function 規(guī)定動(dòng)畫的速度曲線。(linear、ease、ease-in、ease-out、ease-in-out、cubic-bezier(n,n,n,n))
animation-delay 規(guī)定在動(dòng)畫開始之前的延遲。
animation-iteration-count 規(guī)定動(dòng)畫應(yīng)該播放的次數(shù)。
animation-direction 規(guī)定是否應(yīng)該輪流反向播放動(dòng)畫。 (normal、alternate)

DEMO傳送門

Canvas

<canvas>是HTML5新增的元素,作為頁(yè)面圖形繪制的容器,可用于通過(guò)使用JavaScript中的腳本來(lái)繪制圖形。例如,它可以用于繪制圖形,制作照片,創(chuàng)建動(dòng)畫,甚至可以進(jìn)行實(shí)時(shí)視頻處理或渲染,Canvas具有如下特點(diǎn):

  • 依賴分辨率,基于位圖;
  • 不支持事件處理器;
  • 弱的文本渲染能力;
  • 能夠以 .png 或 .jpg 格式保存結(jié)果圖像;
  • 最適合圖像密集型的游戲,其中的許多對(duì)象會(huì)被頻繁重繪;

大多數(shù) Canvas 繪圖 API 都沒(méi)有定義在 <canvas> 元素本身上,而是定義在通過(guò)畫布的getContext()方法獲得的一個(gè)“繪圖環(huán)境”對(duì)象上。Canvas API也使用了路徑的表示法。但是,路徑由一系列的方法調(diào)用來(lái)定義,而不是描述為字母和數(shù)字的字符串,比如調(diào)用 beginPath()arc() 方法。一旦定義了路徑,其他的方法,如 fill(),都是對(duì)此路徑操作。

DEMO傳送門

SVG

SVG是英文Scalable Vector Graphics的縮寫,意為可縮放矢量圖形,用來(lái)定義用于網(wǎng)絡(luò)的基于矢量的圖形,其使用 XML 格式定義圖像,并且具有如下特點(diǎn):

  • 不依賴分辨率,基于矢量圖;
  • 支持事件處理器;
  • 最適合帶有大型渲染區(qū)域的應(yīng)用程序(比如谷歌地圖);
  • 復(fù)雜度高會(huì)減慢渲染速度(任何過(guò)度使用 DOM 的應(yīng)用都不快);
  • 不適合游戲應(yīng)用;

來(lái)看一個(gè)簡(jiǎn)單的示例,用SVG畫了一個(gè)圓:

<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 代碼以 <svg> 元素開始,包括開啟標(biāo)簽 <svg> 和關(guān)閉標(biāo)簽 </svg> 。這是根元素。widthheight 屬性可設(shè)置此 SVG 文檔的寬度和高度。version 屬性可定義所使用的 SVG 版本,xmlns 屬性可定義 SVG 命名空間。

SVG 的 <circle> 用來(lái)創(chuàng)建一個(gè)圓。cxcy 屬性定義圓中心的 x 和 y 坐標(biāo)。如果忽略這兩個(gè)屬性,那么圓點(diǎn)會(huì)被設(shè)置為 (0, 0)。r屬性定義圓的半徑。

下面主要是介紹SVG中的幾個(gè)用于動(dòng)畫的元素,它們分別是:

<animate>:通常放置到一個(gè)SVG圖像元素里面,用來(lái)定義這個(gè)圖像元素的某個(gè)屬性的動(dòng)畫變化過(guò)程;
<animateMotion>:元素也是放置一個(gè)圖像元素里面,它可以引用一個(gè)事先定義好的動(dòng)畫路徑,讓圖像元素按路徑定義的方式運(yùn)動(dòng);
<animateTransform>:元素對(duì)圖形的運(yùn)動(dòng)和變換有更多的控制,它可以指定圖形的變換、縮放、旋轉(zhuǎn)和扭曲等;
<mpath>:元素的用法在上面的例子里出現(xiàn)過(guò),它是一個(gè)輔助元素,通過(guò)它,<animateMotion>等元素可以引用一個(gè)外部的定義的<path>。讓圖像元素按這個(gè)<path>軌跡運(yùn)動(dòng);

DEMO傳送門

WebGL

WebGL使得網(wǎng)頁(yè)在支持HTML <canvas>標(biāo)簽的瀏覽器中,不需要安裝任何插件,便可以使用基于 OpenGL ES 2.0 的 API 在 canvas 中進(jìn)行3D渲染。 WebGL 程序由JavaScript的控制代碼,和在計(jì)算機(jī)的圖形處理單元(GPU)中執(zhí)行的特效代碼(shader code,渲染代碼) 組成。

WebGL.png

WebGL 本質(zhì)上是基于光柵化的 API,而不是基于 3D 的 API。WebGL 只關(guān)注兩個(gè)方面,即投影矩陣的坐標(biāo)和投影矩陣的顏色。使用 WebGL 程序的任務(wù)就是實(shí)現(xiàn)具有投影矩陣坐標(biāo)和顏色的 WebGL 對(duì)象即可??梢允褂谩爸鳌眮?lái)完成上述任務(wù)。頂點(diǎn)著色器可以提供投影矩陣的坐標(biāo),片段著色器可以提供投影矩陣的顏色。

由于WebGL的體系比較龐大,三言兩語(yǔ)說(shuō)不完,所以以下僅提供各種傳送門了(不許說(shuō)我懶?。。?br> WebGL 參考資料
WebGL API

幾個(gè)常用的動(dòng)畫庫(kù)

Ani.js -- 基于CSS動(dòng)畫的生命處理庫(kù)
Dynamics.js -- 創(chuàng)建具有物理運(yùn)動(dòng)效果動(dòng)畫的js庫(kù)
Animate.css -- 齊全的CSS3動(dòng)畫庫(kù)
Three.js -- 讓用戶通過(guò)javascript入手進(jìn)入搭建webgl項(xiàng)目的類庫(kù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一:在制作一個(gè)Web應(yīng)用或Web站點(diǎn)的過(guò)程中,你是如何考慮他的UI、安全性、高性能、SEO、可維護(hù)性以及技術(shù)因素的...
    Arno_z閱讀 1,366評(píng)論 0 1
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,150評(píng)論 25 708
  • 譯者序:原文GPU Animation: Doing It Right,發(fā)表于2016年12月6日,本文是對(duì)該篇的...
    smilewalker閱讀 1,721評(píng)論 0 8
  • 最近看到一篇關(guān)于GPU動(dòng)畫的神文,原文地址:https://www.smashingmagazine.com/20...
    purple_force閱讀 3,681評(píng)論 1 6
  • 【日精進(jìn)打卡第4天】 【知~勤學(xué)】 1、《六項(xiàng)精進(jìn)》大綱1遍,共8遍 2、《大學(xué)》大綱1遍,共8遍 【行~實(shí)踐】 ...
    做自己我就是這樣閱讀 347評(píng)論 0 0

友情鏈接更多精彩內(nèi)容