本文介紹使用css3的animation畫一個太陽系行星公轉的動畫,再加以改進,討論如何畫橢圓的運行軌跡。然后分析京東和人人網使用animation的實際案例,最后結合css3的clip-path做一些比較特別的動畫。
太陽系最終的效果圖如下:

css3的animation是通過關鍵幀的形式做出來的,首先設定一個動畫的運行時間,然后在這個時間軸上的若干位置處插入關鍵幀,瀏覽器根據關鍵幀設定的內容做過渡動畫。animation常結合transform屬性進行制作。以一個簡單的例子說明,以一個div,讓其從左到右運動,如下圖左所未(沒有動畫請刷新下頁面)
先用css畫出靜態的圖,然后再加動畫的屬性。整個工程完整的代碼見這個Demo。html如下:
<div class='space'> <div class='wheel'> <span class='line'></span> </div> </div>
在輪子wheel加一個動畫的屬性,
.wheel{
animation: move 3s linear infinite;
}
這個的意思是動畫的名字是move,時間軸是3s,速度是勻速,播放次數無限。然后move的關鍵幀keyframes如下:
@keyframes move{
100%{ transform: translateX(350px); } }
即播放到末尾的時候,向X軸右移350px。在0%的時候值0,100%的時候值為350px,時間為3s,還有一個速度曲線的屬性,根據這些信息做過渡動畫。如果指定速度為線性linear,則動畫的過渡效果是勻速的,對於上面來說就是勻速右移。默認的速度曲線為ease,就是漸進和漸出,中間播放比較快。
然后再給輪子添加一個滾動的效果rotate,用運行的距離除以輪子的周長得出需要滾動多少圈,即375 / (25 * 3.1415926 * 2) * 360 = 859.4度,也就是在這個區間向右移動的同時加上自轉的效果,所以給transform添加多一個rotate的屬性。
transform: translateX(350px) rotate(859.4deg);
這樣就可以了:

這就是css3的animation動畫,結合transform的大小、旋轉、位移、斜切,通過兩三行代碼,便可做出很多有趣的效果。
接下來討論太陽系的制作,跟上面不同的地方是行星是圍繞着太陽轉的,而輪子是圍繞着自己的圓心轉的,也就是說他們轉的基點不同。可以看出,transform的基點默認是本身的中心center,所以我們要改變行星的進行轉換的中心點transform-origin。完整的Demo。太陽系的html結構如下:
<div class="galaxy">
<div class='sun'></div>
<div class='mercury'></div>
<div class='venus'></div>
<div class='earth'></div>
</div>
太陽位於div galaxy的中間,讓其它行星位於太陽的右邊排成一條線。設置galaxy的width和height都為1300px。sun圖片的大小為100px*100px,所以sun的left值和top值都為(1300 - 100) / 2 = 600px,這樣sun就位於中間位置。設置水星mercury的left值為700px,top為625px,這樣水星就位於太陽偏右的位置。然后再設置transform-origin:
transform-origin: -50px 25px;
transform-origin的原點是作用的元素左上角位置,所以往左移(700 - 1300 / 2) = 50px,往下移60 / 2 = 30px(60為水星高度),水星轉換的基點就變成了太陽的中心,在此基礎上進行旋轉:
animation: rotation 2.4s linear infinite; @keyframes rotation{ to{ transform: rotate(1turn); } }
注意這里改變了同義的屬性,0%和100%分別換成from和to,360deg換成1turn。
其它的行星,也按照這種方法進行設置,計算稍微繁瑣。公轉的周期以地球10s為基准,其它按比例換算。這樣就可以做出一個太陽系公轉的圖,原理很簡單,效果卻很好。
注意到行星運行的軌跡其實是橢圓形的,上面是用了正圓形。因此,下面討論如何做一個橢圓的運行軌跡。查看完整的Demo。效果圖如下:

上面的橢圓在Y軸上被壓扁了,可以考慮在Y軸上添加一個位移變換,原理如下圖所示,首先將地球的初始位置放到橢圓和其短軸的交點處,然后transform-origin設置為半徑為800px的圓心的位置,但運行時間為50%即到初始位置對面的時候,插入一個關鍵幀:做一個位移轉換,向y軸負方向移動200px,這樣就可以形成一個半橢圓的軌跡,到了100%的時候逐漸恢復為初始值0,跟前面的半橢圓相反,就可以完成一個完整的橢圓軌跡。

需要在earth的外面包一層div,用來設置translateY的效果,因為這個效果的時間曲線需要設置為ease-in-out漸進漸出的效果,讓橢圓運行起來更加的順暢。html的結構如下:
<div class='planet'>
<div class='origin-circle'></div>
<div class='sun'></div>
<div class='track'></div>
<div class='moveY'>
<div class='earth'></div>
</div>
</div>
給moveY添加一個translateY的動畫,其它的一樣。
.moveY{ animation: moveY 2s ease-in-out infinite alternate; /* */ }
@keyframes moveY{
to{
transform: translateY(-200px);
}
}
注意這里將moveY的周期設置為旋轉的一半,同時使用了一個transition-direction為alternate的屬性,alternate意為交替,效果等同於
@keyframes moveY{ 0%,100%{ transform: translateY(0px); } 50%{ transform: translateY(-200px); } }
細心的讀者會發現,這里的運行軌跡並不是嚴格的橢圓,旋轉是勻速的,但是在y軸上的投影即在y軸上的速度是一條曲線,這條曲線理論上可以用貝賽爾曲線模擬出來,animation的速度參數改用cubic-bezier去模擬,ease-in-out等同於cubic-bezier(0.4,0,0.6,1)。通過一些數學換算理論上是可以模擬的,這里不再深入討論。
還可以繼續優化,讓地球自轉,自轉的方法,可以在地球的div外面再包多一個div,讓公轉的動畫由外層的div實現,而自轉由地球的div完成。讀者可以自行嘗試。
接下來,討論人人網、京東使用animation做動畫的實例。
打開人人網的公共主頁,當鼠標放到四個圖標上面和離開的時候會有波浪形的動畫:

這個動畫研究下源代碼,可以發現是用了一張長圖,由很多張小圖組成,每張小圖就是這個動畫的一幀。當鼠標hover時,添加一個active類,這個類的css里面使用animation,改變這張長圖的translate位移,如下:
.active{ animation: movedown 500ms steps(12) forwards; } @keyframes moveup{ to{ background-position: 0 -1800px; } }
上面設置動畫的名稱為movedown,播放時間500ms,forwars的意思是播放完成后,動畫保持最后一幀的樣式,相反的是backwards,和剛開始播放的時候一樣,默認值是none,不會保持動畫的樣式。這個動畫的重點在於steps,steps(12)的目的是設置播放12幀,這張長圖用來播放hover動畫是由12圖小圖組成的,對應12幀,因此每播放一幀,background-position的位置剛好指向下張小圖的位置,這樣就連成了一個連貫的逐幀動畫。類似的動畫可以見這個(來自jsfiddle),這個是實時的動畫,老的瀏覽器可能會不支持。

第二個案例是京東首頁的時鍾,下面是一個實時的demo:
這個案例的技術手段是用了animation結合transform的rotate,跟上面的太陽系的技術手段一樣,這里不再敘述,主要是位置的計算比較瑣碎,源碼可見這里。
上面的案例都是用了transform,下面使用clip-path做一些比較有趣的動畫。關於clip-path的描述,可見筆者的另外一篇文章: 《使用css3新屬性clip-path制作小圖標》。這里簡單作下說明,clip-path是用來裁剪的,如對一個div應用clip-path: circle(40% at 50% 50%)——裁剪的路徑為一個圓,圓心在div的(50%, 50%)的位置,半徑為40%,效果就是讓這個div的可見區域為這個圓,圓外的像素瀏覽器都不會進行渲染。
使用transform可以做一些位移、大小、旋轉的動畫,而使用clip-path能夠做一些形狀變化的動畫。效果如下,當鼠標放上去的時候,從一個圓沿半徑方向逐漸外擴直至顯示完整的照片。右下圖為實時演示,請嘗試把鼠標放上去(請使用chrome/safari瀏覽器)
html結構就是一張照片:
<img src="http://images2015.cnblogs.com/blog/818663/201510/818663-20151015222926741-365571868.png" alt=""/>
css如下:
img{
clip-path: circle(40% at 50% 50%);
-webkit-clip-path: circle(40% at 50% 50%);
transition: all 400ms ease;
cursor: pointer;
}
img:hover{
clip-path: circle(75% at 50% 50%);
-webkit-clip-path: circle(75% at 50% 50%);
}
這里使用了transition動畫,常和hover結合使用做過渡動畫。transition: all 400ms ease這句設置transition作用在該元素所有CSS屬性上,你也改成clip-path,只作用在clip-path這個屬性,過渡時間為400ms,使用ease漸入漸出的效果和animatio一樣。當hover的時候,就過渡到 clip-path: circle(75% at 50% 50%),也就是顯示的半徑從40%到75%,hover結束時,再恢復成原先的40%,因此就有了上面的效果。當然clip-path還可以做很多有趣的變形動畫,例如從四角變成五角,這里只是拋磚引玉,更多動畫的效果讀者可自行上網查找。
最后,做個總結。這篇文章介紹了使用animation結合transform做動畫的原理和語法,並且分析了幾個關鍵的要點,包括transform的坐標軸、轉換的原點,還有,可以通過嵌套幾個動畫做出復合的效果,接着展示了兩個實際的生產案例,最后對transition和clip-path做了一個變形的動畫。css3的動畫效果不限於此,讀者可上網搜索其它更有趣的案例。例如這個20 impressive css3 techniques libraries and examples。
個人博客: http://yincheng.site/css3-animation
參考:
1. https://css-tricks.com/almanac/properties/a/animation/ css tricks上關於animation的介紹
2. https://css-tricks.com/almanac/properties/t/transition/ css tricks上關於transition的介紹
