[譯] CSS Animations 的提示與技巧(MDN)

始發於個人博客 ryougifujino.com,歡迎訪問留言。javascript

CSS Animations 的出現讓你在文檔和應用上建立難以想象的動畫效果成爲了可能。可是,有一些你想實現的東西可能並不是如此淺顯,或者說你不能輕易的想出一種聰明的方式來完成它們。這篇文章包含了一系列的提示與技巧來使得你的工做更加容易,其中包括瞭如何讓一個已經中止的動畫從新運行起來。css

讓動畫再次運行起來

CSS Animations 的規範沒有提供讓動畫再次運行起來的方法。並不存在適用於元素的魔法方法requestAnimation(),甚至即便你把元素的animation-play-state設置爲"running"也無濟於事。你得用一種聰明的技巧來使得已經中止的動畫再次回放。html

咱們將介紹一種咱們認爲足夠穩定可靠的方法給你。java

HTML 內容

首先,讓咱們建立一個用於執行動畫的<div>和一個用於播放(或者說回放)動畫的按鈕。ide

<div class="box">
</div>

<div class="runButton">Click me to run the animation</div>

複製代碼

CSS 內容

如今讓咱們用CSS定義動畫自己。一些並不重要的CSS(例如播放按鈕自身的樣式)出於簡潔的考慮並不會在這裏出現。函數

@keyframes colorchange {
  0% { background: yellow }
  100% { background: blue }
}

.box {
  width: 100px;
  height: 100px;
  border: 1px solid black;
}

.changing {
  animation: colorchange 2s;
}
複製代碼

這裏有兩個 class。"box" class 是盒子外觀的基礎描述,並不包含任何動畫信息。動畫細節都被包含在"changing" class 裏,它描述了:一個叫colorchange@keyframes將會被運用在一個2秒鐘的做用於盒子的動畫過程之中。動畫

JavaScript 內容

下一步咱們將看看 JavaScript 所作的工做。這項技術的核心位於play()函數之中,這個函數將在用戶點擊「Run」按鈕時被回調。ui

function play() {
  document.querySelector(".box").className = "box";
  window.requestAnimationFrame(function(time) {
    window.requestAnimationFrame(function(time) {
      document.querySelector(".box").className = "box changing";
    });
  });
}
複製代碼

看起來真的很奇怪,不是嗎?這是由於再次播放動畫的惟一方法就是刪除動畫效果,讓文檔從新計算樣式來使得它明白你已經進行了刪除,而後再把動畫效果添加回元素中。爲了讓這一切發生,咱們必需要有創造性。spa

這是當play()方法被調用時發生了什麼:.net

  1. 盒子的class被重置爲了"box"。這個動做把其餘當前運用在盒子上的 class 都給刪除了,包括處理動畫的"changing"class。換而言之,咱們正把盒子上的動畫效果給移除掉。可是,在樣式從新計算完成以前,或反應改變的刷新發生以前,class 列表的變動都不會生效。
  2. 爲了確保樣式已經被從新計算,咱們使用window.requestAnimationFrame()來指定一個回調。這樣咱們的回調就會在文檔下一次重繪以前執行。問題在於,由於是發生重繪前的,因此樣式的重計算尚未真的發生!因此……
  3. 咱們的回調聰明地第二次調用了requestAnimationFrame()!這一次,回調運行於第二次下一次重繪以前,這時第一次重繪已經完成,因此能夠確保樣式的重計算已經發生。這個回調把changing class 添加回了盒子之上,使得重繪後動畫將再次開始。

固然,咱們還須要給咱們的"Run"按鈕添加一個事件處理器:

document.querySelector(".runButton").addEventListener("click", play, false);
複製代碼

中止動畫

僅僅刪除應用於元素的animation-name就會讓元素跳轉到它的下一個狀態。若是你想在動畫完成時再讓它中止,那麼你可能須要嘗試另外一種不一樣的方法。主要技巧以下:

  1. 讓你的動畫越獨立越好。意思是你不該該依賴於animation-direction: alternate。取而代之,你應該顯式地寫一個 keyframe 動畫來模擬這個過程。
  2. animationiteration事件發生時,用 JavaScript 清理正在被使用的動畫。

下面的 demo 展現瞭如何實現上述的 JavaScript 技術:

.slidein {
  animation-duration: 5s;
  animation-name: slidein;
  animation-iteration-count: infinite;
}

.stopped {
  animation-name: none;
}

@keyframes slidein {
  0% {
    margin-left: 0%;
  }
  50% {
    margin-left: 50%;
  }
  100% {
    margin-left: 0%;
  }
}
複製代碼
<h1 id="watchme">Click me to stop</h1>
複製代碼
let watchme = document.getElementById('watchme')

watchme.className = 'slidein'
const listener = (e) => {
  watchme.className = 'slidein stopped'
}
watchme.addEventListener('click', () =>
  watchme.addEventListener('animationiteration', listener, false)
)
複製代碼

Demo地址

原文地址(MDN) 更新於Mar 23, 2019, 6:23:51 PM。部分live demo不能連接過來,請前往原文進行查看。

相關文章
相關標籤/搜索