使用css實現動畫方法與動畫性能分析

css3新增了transition與animation兩種方式可實現動畫,那麼在出現transition與animation以前,有兩種方式實現動畫:一種是使用css的hover僞類屬性方式,另一種是使用js改變css屬性方式;接下來我會介紹transition與animation的使用方法以及解決了什麼問題,最後會分析咱們爲何使用transition與animation實現動畫要比js方式性能要高效!javascript

transition的使用


咱們以前使用hover僞類實現動畫,是如下效果:css

.div {
    width:100px;
    height:100px;
    background:red;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}
複製代碼

能夠看出元素的狀態變化是當即發生,沒有一個過渡的過程,也就是沒有時間軸;那麼css3新增的transition(過渡)也就是解決了這個問題;

.div {
    width:100px;
    height:100px;
    background:red;
    transition:3s;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}

複製代碼

如上圖,加上transition,div狀態的變化就有了一個過渡過程;
transition 是 transition-property(狀態發生變化的屬性),transition-duration(過渡所用的時間),transition-timing-function(過渡變化的速度) 和 transition-delay(延遲多長時間開始過渡) 的一個簡寫屬性。
上例中,3s就是過渡所用時間,咱們沒有設置transition-property,就會默認全部發生變化的狀態都會過渡,若是咱們只須要某個特定屬性發生過渡變化,只須要寫明就能夠了;

.div {
    width:100px;
    height:100px;
    background:red;
    transition:width 3s;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}

複製代碼

若是咱們想要多個屬性一塊兒過渡,而不是所有變化的屬性過渡,可以使用逗號分隔開;

.div {
    width:100px;
    height:100px;
    background:red;
    transition:width 3s, background 3s;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}

複製代碼

css3 還給過渡增長了延遲時間與過渡速度的功能;過渡速度經常使用的有ease(速度逐漸變慢,這是默認值)、linear(均速)、ease-in(以慢速開始)、ease-in-out(慢速開始、再快速、再慢速)、cubic-bezier函數(可自定義速度);
假如咱們想要width先過渡,2s後height再過渡,2s後顏色再過渡,可使用下面寫法;

.div {
    width:100px;
    height:100px;
    background:red;
    transition:width 3s, height 2s 3s ease-in-out, background 3s 5s ease-in-out;
}
.div:hover {
    width:200px;
    height:200px;
    background:green;
}

複製代碼

transition須要注意的事項:

  • transition須要事件觸發,好比hover事件,click事件,所以不能在網頁加載時自動發生;
  • transition是一次性的,不能重複發生,觸發屢次觸發;
  • transition只能定義開始狀態和結束狀態,不能定義中間狀態,也就是說只有兩個狀態。 animation的出現就解決了transition上面的問題;

animation的使用


animation能夠實現transiton的效果,看下面代碼;html

.div {
    width:100px;
    height:100px;
    background:red;
}
.div:hover {
    
    animation: move 3s forwards;
}
@keyframes move {
    100% {
         background: green;
          width:200px;
          height:200px;
    }
}
複製代碼

animation 比 transition更強大,不須要事件觸發,能夠進入頁面就開始加載,也能夠無限循環;

.div {
    width:100px;
    height:100px;
    background:red;
  animation: move 3s infinite alternate;
}
@keyframes move {
    100% {
         background: green;
          width:200px;
          height:200px;animation-name
    }
}
複製代碼

animation是個複合屬性,子屬性有:

  • animation-name 動畫的名字,就是上面的move,須要使用keyframes關鍵字定義move的效果;
  • animation-duration 動畫的持續時間,就是上面的3s
  • animation-timing-function 動畫的變化速度,和transition的animation-timing-function值是同樣
  • animation-delay 動畫延遲執行的時間
  • animation-direction 動畫執行的方向;動畫循環播放時,每次都是從結束狀態跳回到起始狀態,再開始播放;animation-direction能夠改變這種循環方向,值有:normal、reverse、alternate、alternate-reverse
  • animation-iteration-count 動畫執行的次數,能夠是數字,也能夠是infinite(無限循環);
  • animation-fill-mode 默認狀況下動畫結束之後,會當即從結束狀態跳回到起始狀態。若是想讓動畫保持在結束狀態,須要使用animation-fill-mode屬性,值爲forward。
  • animation-play-state 動畫是否運行或者暫停;running:當前動畫正在運行;paused:當前動畫以被中止;
    目前,IE 10和Firefox(>= 16)支持沒有前綴的animation,而chrome不支持,因此必須使用webkit前綴。
.div {
    width:200px;
    height:200px;
    background:red;
    margin: 100px auto;
    -webkit-animation: move 3s infinite alternate;
    animation: move 3s infinite alternate;
}
@keyframes move {
  0% {
    background: red;
    transform: scale(0.4);
    }  
  50% {
    background: yellow;
    border-radius: 100%;
  }
  100% {
    background: green;
    transform: scale(1.5);
    }
}
複製代碼

要分析動畫優化,那不得不提下瀏覽器對頁面的渲染原理;java

動畫性能分析

瀏覽器對頁面的渲染原理,可分爲如下步驟: 1.根據HTML構建DOM樹;
2.根據CSS構建CSSOM樹;
3.將DOM樹與CSSOM樹合成一個渲染樹(render tree);
4.Layout佈局,包括文檔流、盒模型、計算大小和位置;
5.Paint繪製,包括邊框顏色、文字顏色、陰影等畫出來;
6.Compose合成,根據層疊關係展現畫面;
css3

當DOM或者CSSOM樹被修改,以上過程再被從新執行一遍,這樣才能計算出哪些像素在頁面從新渲染;當頁面從新渲染時,像素至屏幕管道中的關鍵點有如下5個部分;

可是不是每次渲染都會通過以上5個部分,有如下三種方式:

通常來講,咱們會使用 JavaScript 來實現一些視覺變化的效果。好比用 jQuery 的 animate 函數作一個動畫、對一個數據集進行排序或者往頁面裏添加一些 DOM 元素等。 若是您修改元素的「layout」屬性,也就是改變了元素的幾何屬性(例如寬度、高度、左側或頂部位置等),那麼瀏覽器將必須檢查全部其餘元素,而後「自動重排」頁面。任何受影響的部分都須要從新繪製,並且最終繪製的元素需進行合成。
你能夠打開控制檯中選擇rendering,選中paint flashing(繪製,綠色高亮區域)、layout shift regions(佈局,藍色高亮區域)

能夠看下面的例子:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style> div { width: 100px; height: 100px; background: red; float: left; } div:nth-child(2) { background: yellow; } div:nth-child(3) { background:black; } </style>
</head>
<body>
<div id="div"></div>
<div></div>
<div></div>
<script> let div = document.getElementById("div"); setInterval(()=>{ div.style.display='none' },1000) </script>
</body>
</html>

複製代碼

執行代碼以下:web

從上面能夠看到,js引發了元素位置的變化,是頁面渲染元素通過了layout、paint;

若是您修改「paint only」屬性(例如背景圖片、文字顏色或陰影等),即不會影響頁面佈局的屬性,則瀏覽器會跳過佈局,但仍將執行繪製。

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 100px;
      height: 100px;
      background: red;
      float: left;
    }
    div:nth-child(2) {
      background: yellow;
    }
    div:nth-child(3) {
      background:black;
    }
    div:hover {
      background:deeppink;
    }
  </style>
</head>
<body>
<div id="div"></div>
<div></div>
<div></div>
</body>
</html>

複製代碼

從上圖能夠看出,改變背景色會引發paint,可是不會引發layout;

若是您更改一個既不要佈局也不要繪製的屬性,則瀏覽器將跳到只執行合成。 這個最後的版本開銷最小,最適合於應用生命週期中的高壓力點,例如動畫或滾動。

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    #div {
      width: 100px;
      height: 100px;
      background: red;
      margin: 100px auto;
      -webkit-animation: change 3s infinite alternate;
      animation: change 3s infinite alternate;
    }
    @keyframes change {
      0% {
        transform: translateX(100PX);
      }
      50% {
        transform: translateX(300PX);
      }
      100% {
        transform: translateX(500PX);
      }
    }
  </style>
</head>
<body>
<div id="div"></div>
</body>
</html>

複製代碼

從上圖中可看到動畫只有剛開始加載的時候回paint,後面只是合成,並無paint了;

參考文檔:css動畫簡介 animation tricks
結束語:感謝飢人谷,以上文章記錄了本身在飢人谷的學習內容;chrome

相關文章
相關標籤/搜索