takumifukasawa’s blog

WebGL, Shader, Unity, UE4

CSSスプライトアニメーションをGPUレンダリングさせる

※内容は以前書いたこちらの記事と同じでさらに文章に校正を加えたものになります。jsdo.itをデモとして使っていたのですがjsdo.itがクローズになってデモが動作しなくなったのでデモをcodepenに移したためです。

CSSスプライトアニメーションをGPUレンダリングさせる - Qiita

スプライトアニメーションと再描画

CSSでスプライト画像の連番アニメーションを実装する場合、background-positionをずらす方法を使っていました。しかし、同じ画面内でサイズの大きい画像のスプライトアニメーションをいくつも動かしたい場面があり、パフォーマンスがネックになりました。

実際、background-positionのcss animationはGPUレンダリングではないので再描画処理が走ってしまいます。chromeのデバッガーツールでRenderingPaint Flashingを見ると、このように再描画処理が走っているのがわかります。

f:id:takumifukasawa:20200328232048p:plain

@keyframes sprite-image {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: 0 -1064px;
  }
}

.sprite {
  width: 400px;
  height: 266px;
  margin: 15px;
  background-image: url(https://user-images.githubusercontent.com/947953/77824893-2f663480-7149-11ea-873b-9fda24fe1022.jpg);
  background-size: 400px 1064px;
  animation: sprite-image 1s steps(4) infinite;    
}

css transformを使うことで再描画を防ぐ

そこでGPU処理が適用されるcss transformを使った方法を試してみました。before要素の大きさをスプライト画像と同じ大きさにし、背景にスプライト画像をあて、animationでtransformを操作することにより、background-positionの時と同じDOM構造のままcssを変更するのみで実現できました。

先ほどと同じようにchromeのデバッガーツールを見てみると、再描画が走っていないことがわかります。この方法によって、background-positionを使った時よりも描画負荷を軽減することができました。

f:id:takumifukasawa:20200328232059p:plain

こちらがデモになります。

See the Pen 【CSS】Sprite Animation by GPU Rendering by takumifukasawa (@takumifukasawa) on CodePen.

cssの抜粋です。

@keyframes sprite-image {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(0, -100%);
  }
}

.sprite {
  overflow: hidden;
  width: 400px;
  height: 266px;
  margin: 15px;

  // animationでtransformのtranslateを動かす
  &:before {
    content: "";
    display: block;
    width: 400px;
    height: 1064px;
    background-image: url(https://user-images.githubusercontent.com/947953/77824893-2f663480-7149-11ea-873b-9fda24fe1022.jpg);
    background-size: 400px 1064px;
    animation: sprite-image 1s steps(4) infinite;
  }
}