怕標題起的有點大,下述技巧若是你已經掌握了看看就好,歡迎斧正,本文但願經過介紹一些 CSS 不太經常使用的技巧,輔以一些實踐,讓讀者能夠更加深刻的理解掌握 CSS 動畫。css
廢話少說,直接進入正題,本文提到的動畫不加特殊說明,皆指 CSS 動畫。html
(寫完文章才發現這裏應該叫正反旋轉相消,圖都截完了,你們內心清楚就好)git
在動畫中,旋轉是很是經常使用的屬性,github
{ transform: rotate(90deg); }
那旋轉有一些什麼高級點的技巧呢?固然是能夠改變 transfrom-origin
,改變旋轉中心點啦。chrome
開個玩笑,改變旋轉中心點這個估計你們都知道了,這裏要介紹的技巧是利用父級元素正反兩個方向的旋轉,來製做一些酷炫的 3d 效果。瀏覽器
首先假設一下場景,咱們有這樣的一層 HTML 結構:函數
<div class="reverseRotate"> <div class="rotate"> <div class="content">正負旋轉相消3D動畫</div> </div> </div>
樣式以下:工具
.content
內是咱們的主要內容,好了,如今想象一下,若是祖先元素 .rotate
進行正向 linear 360° 旋轉,父級元素 .reverseRotate
進行反向 linear 360° 旋轉,效果回是啥樣?性能
CSS 代碼以下:
.rotate { animation: rotate 5s linear infinite; } .reverseRotate { animation: reverseRotate 5s linear infinite; } @keyframes rotate { 100% { transform: rotate(360deg); } } @keyframes reverseRotate { 100% { transform: rotate(-360deg); } }
神奇!由於一正一反的旋轉,且緩動函數同樣,因此整個 content
看上去依然是靜止的!注意,這裏整個 content
靜止的很是重要。
有讀者看到這裏就要罵街了,做者你個智障,靜止了不就沒動畫了嗎?哪來的動畫技巧?
別急!雖然看上去是靜止的,可是其實祖先兩個元素都是在旋轉的!這會看上去風平浪靜的效果底下實際上是暗流涌動。用開發者工具選取最外層祖先元素是這樣的:
既然如此,咱們繼續思考,若是我在其中旋轉的一個祖先元素上,添加一些別的動畫會是什麼效果?想一想就很刺激啊。
爲了和文案裏面的 3D 動畫扯上關係,咱們先給這幾個元素添加 3D 轉換:
div { transform-style: preserve-3d; perspective: 500px; }
接着,嘗試修改上面的旋轉動畫,在內層旋轉上額外添加一個 rotateX:
@keyframes rotate { 0% { transform: rotateX(0deg) rotateZ(0deg); } 50% { transform: rotateX(40deg) rotateZ(180deg); } 100% { transform: rotateX(0deg) rotateZ(360deg); } }
效果以下:
Wow,這裏須要好好理解一下。因爲內容 content
層是靜止的但其實外層兩個圖層都在旋轉,經過設置額外的 rotateX(40deg)
,至關於疊加多了一個動畫,因爲正反旋轉抵消了,全部整個動畫只能看到旋轉的 rotateX(40deg)
這個動畫,產生了上述的效果。
好的,繼續下一個小技巧。
有的時候咱們頁面存在一些具備相同動畫的元素,爲了讓動畫不那麼死板,咱們能夠給相同的動畫,賦予不一樣的緩動函數,來達到動畫效果。
假設咱們有以下的結構:
<div class="container"> <div class="ball ball1"></div> <div class="ball ball2"></div> <div class="ball ball3"></div> </div>
樣式以下:
咱們給它們相同的動畫,可是賦予不同的緩動函數(animation-timing-function),就像這樣:
.ball1 { animation: move 1s ease-in infinite alternate; } .ball2 { animation: move 1s linear infinite alternate; } .ball3 { animation: move 1s ease-out infinite alternate; } @keyframes move { 100% { transform: translateY(5vw); } }
這樣,一個簡單的 loading 效果就製做好了。(固然這個技巧比較簡單,學會合理運用是關鍵)
緩動函數 timing-function 在動畫中佔據了很是重要的地位。
當你不想使用 CSS 默認提供的 linear
、ease-in
、ease-out
之類緩動函數的,能夠自定義 cubic-bezier(1, 1, 0, 0)
,這裏有個很是好用的工具推薦,下面這個網站,能夠方便的調出你須要的緩動函數而且拿到對應的 cubic-bezier 。
咱們在製做頁面的時候,爲了讓頁面更加有交互感,會給按鈕,陰影,顏色等樣式添加過渡效果,配合 hover 一塊兒使用。
這個是常規思惟,若是咱們的元素一開始是沒有過渡效果,只有 hover 上去纔給它添加一個過渡,又或者一開始元素是有過渡效果的,當咱們 hover 上去時,取消它的過渡,會碰撞出什麼樣的火花呢?
使用這個技巧(也許算不上技巧,純粹好玩),咱們能夠製做出一些有趣的效果,例以下面這個感受是利用就 JS 才完成的動畫,實際上是純 CSS 動畫:
其實就小圓圈是元素默認是帶有 transition
的,只有在 hover 上去的時候,取消它的過渡,簡單的過程:
因爲一開始它的顏色的透明的,而 hover 的時候會賦予它顏色值,可是因爲 hover 時過渡被取消了,全部它會直接顯示。
hover 離開的時候,它的本來的過渡又回來了,這個時候它會從有顏色到透明值緩慢漸變消失。
能夠戳這裏感覺一下:
CodePen Demo -- Cancle transition
這個問題可能有一點難理解。須要瞭解 CSS 動畫渲染優化的相關知識。
先說結論,動畫層級的控制的意思是儘可能讓須要進行 CSS 動畫的元素的 z-index
保持在頁面最上方,避免瀏覽器建立沒必要要的圖形層(GraphicsLayer),可以很好的提高渲染性能。
OK,再一次提到了圖形層(GraphicsLayer),這是一個瀏覽器渲染原理相關的知識(WebKit/blink內核下)。
簡單來講,瀏覽器爲了提高動畫的性能,爲了在動畫的每一幀的過程當中沒必要每次都從新繪製整個頁面。在特定方式下能夠觸發生成一個合成層,合成層擁有單獨的 GraphicsLayer。
須要進行動畫的元素包含在這個合成層之下,這樣動畫的每一幀只須要去從新繪製這個 Graphics Layer 便可,從而達到提高動畫性能的目的。
那麼一個元素何時會觸發建立一個 Graphics Layer 層?從目前來講,知足如下任意狀況便會建立層:
本題中說到的動畫層級的控制,緣由就在於上面生成層的最後一條:
元素有一個 z-index 較低且包含一個複合層的兄弟元素。
這裏是存在坑的地方,首先咱們要明確兩點:
transform: translate3d()
這樣的方式生成一個 Graphics Layer 層。記住這兩點以後,回到上面咱們說的坑。
假設咱們有一個輪播圖,有一個 ul 列表,結構以下:
<div class="container"> <div class="swiper">輪播圖</div> <ul class="list"> <li>列表li</li> <li>列表li</li> <li>列表li</li> <li>列表li</li> </ul> </div>
假設給他們定義以下 CSS:
.swiper { position: static; animation: 10s move infinite; } .list { position: relative; } @keyframes move { 100% { transform: translate3d(10px, 0, 0); } }
因爲給 .swiper
添加了 translate3d(10px, 0, 0)
動畫,因此它會生成一個 Graphics Layer,以下圖所示,用開發者工具能夠打開層的展現,圖形外的黃色邊框即表明生成了一個獨立的複合層,擁有獨立的 Graphics Layer 。
可是!在上面的圖中,咱們並無給下面的 list
也添加任何能觸發生成 Graphics Layer 的屬性,可是它也一樣也有黃色的邊框,生成了一個獨立的複合層。
緣由在於上面那條元素有一個 z-index 較低且包含一個複合層的兄弟元素。咱們並不但願 list
元素也生成 Graphics Layer ,可是因爲 CSS 層級定義緣由,下面的 list 的層級高於上面的 swiper,因此它被動的也生成了一個 Graphics Layer 。
使用 Chrome,咱們也能夠觀察到這種層級關係,能夠看到 .list
的層級高於 .swiper
:
因此,下面咱們修改一下 CSS ,改爲:
.swiper { position: relative; z-index: 100; } .list { position: relative; }
這裏,咱們明確使得 .swiper
的層級高於 .list
,再打開開發者工具觀察一下:
能夠看到,這一次,.list
元素已經沒有了黃色外邊框,說明此時沒有生成 Graphics Layer 。再看看層級圖:
此時,層級關係纔是咱們但願看到的,.list
元素沒有觸發生成 Graphics Layer 。而咱們但願須要硬件加速的 .swiper
保持在最上方,每次動畫過程當中只會獨立重繪這部分的區域。
這個坑最先見於張雲龍發佈的這篇文章CSS3硬件加速也有坑,這裏還要總結補充的是:
GPU 硬件加速也會有坑,當咱們但願使用利用相似 transform: translate3d()
這樣的方式開啓 GPU 硬件加速,必定要注意元素層級的關係,儘可能保持讓須要進行 CSS 動畫的元素的 z-index
保持在頁面最上方。
Graphics Layer 不是越多越好,每一幀的渲染內核都會去遍歷計算當前全部的 Graphics Layer ,並計算他們下一幀的重繪區域,因此過量的 Graphics Layer 計算也會給渲染形成性能影響。
可使用 Chrome ,用上面介紹的兩個工具對本身的頁面生成的 Graphics Layer 和元素層級進行觀察而後進行相應修改。
上面觀察頁面層級的 chrome 工具很是吃內存?好像仍是一個處於實驗室的功能,分析稍微大一點的頁面容易直接卡死,因此要多學會使用第一種觀察黃色邊框的方式查看頁面生成的 Graphics Layer 這種方式。
不少技巧單獨拿出來可能都顯得比較單薄,我以爲最重要的是平時多積累,學會融會貫通,在實際項目中靈活組合運用,最近項目須要一個比較富有科技感的數字計數器,展現在線人數的不斷增長。由於是內部需求,沒有設計稿,靠前端自由發揮。
運用了上面提到的一些小技巧,參考了一些 CodePen 上的效果,整了個下述的 3D 數字計數效果,純 CSS 實現,效果圖以下:
CodePen Demo -- 3d Number Count
這個例子主要是想告訴你們,不少小的細節小的技巧合在一塊兒,是能夠做出很是酷炫的動畫的。
還有一些技巧,感受本文的信息量已經夠大了,因此可能會出個下篇。
系列 CSS 文章彙總在個人 Github ,持續更新,歡迎點個 star 訂閱收藏。
好了,本文到此結束,但願對你有幫助 :)
若是還有什麼疑問或者建議,能夠多多交流,原創文章,文筆有限,才疏學淺,文中如有不正之處,萬望告知。