CSSで描くパーティクルアニメーション

この記事は CSS Advent Calendar 2019 22日目の記事です。
CSSでこんなこともできるんだなぁぐらいの軽い気持ちでみていただけますと幸いです。

<h1>パーティクルアニメーションとは
<p>パーティクルとは粒子のことで、粒子に対して色々な動きや変化を与えることで、
神秘的な演出や派手な演出・キュートな演出など様々な表現ができます。

<h1>CSSで描いてみた

以下、制作したパーティクルアニメーションのサンプルとなります。

※Qita上では動作が重いので、サンプル右上のCodePenロゴかDEMOをクリックしてご覧ください。
※SPではあまり綺麗に映りません…

<a href="https://hisamikurita.github.io/perticle-rotation-01/dist/">● DEMO</a>

<p class="codepen" data-height="500" data-theme-id="dark" data-default-tab="result" data-user="hisamikurita" data-slug-hash="JjjJvNY" style="height: 357px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Particle Rotation #02">
  <span>See the Pen <a href="https://codepen.io/hisamikurita/pen/JjjJvNY">
  Particle Rotation #02</a> by Hisami Kurita (<a href="https://codepen.io/hisamikurita">@hisamikurita</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

<h1>解説

サンプルはCSSアニメーションを使用して動かしています。
以下、ポイントとなる技術的な部分を解説していきたいと思います。

<h2>Pug + SCSS

メタ言語のPugとSCSSを使用しています。
主にfor文でdivを100~生成したり、div一つ一つに固有のスタイルを当てるために使用します。

```Pug:Pug
- for (var i = 0; i < 200; i++)
    div.rotate
      div.flip_rotate
        div.flip_pos
          div.flip
```
コンパイルします↓

```HTML:HTML

<div class="rotate">
  <div class="flip_rotate">
    <div class="flip_pos">
        <div class="flip"></div>
    </div>
  </div>
</div>
<!-- 上記の複数のdivが200個生成されます。 -->
```

```SCSS:SCSS
@for $i from 1 through 200 {
  .rotate:nth-of-type(#{$i}) {
  }
}
```
コンパイルします↓

```CSS:CSS

.rotate:nth-of-type(1) {
}
.rotate:nth-of-type(2) {
}
.rotate:nth-of-type(3) {
}
/* 上記のクラス指定を200番目まで固有に指定することができます。 */
```
メタ言語を使用しないで、HTMLとCSSのみでも書くことも可能ですが、流石に100~固有にスタイルを当てていくのは大変だと思います:sweat_smile:

<h2>ランダム関数

パーティクルアニメーションはランダムな値を与えたい時が多いです。
例えば、この要素は速く動かしたいけど別の要素はゆっくり動かしたいことがよくあります。
その時に`random()`を使用します。

```SCSS:SCSS
animation: rotation linear infinite reverse;
animation-duration: random(50000) + 20000 + ms;
```
サンプルでは円周上を回転させる際のCSSアニメーションにかかる時間の秒数に対して、
上記のように引数`50000`の中でランダムな値が出るように設定しています。
更に、`20000`を足すことで、`20001ms~70000ms`の範囲でランダムな値が出るように設定しています。このように設定することで極端に遅いアニメーションをさせないようにしています。

<h2>animation-delayに負の値を指定する

`animation-delay`は負の値を指定することで、アニメーション周期の指定した時間から直ちに開始されます。

```SCSS:SCSS
animation: rotation linear infinite reverse;
animation-delay: random(9999) + 50000 * -1ms;
```
サンプルでは円周上を回転させる際のCSSアニメーションの開始時間に対して、
上記のように負の値を設定しています。
更に、ランダム関数を使用することで`-40001ms~-49999ms`の範囲でランダムな値が出るように設定しています。`animation-duration`は`20001ms~70000ms`の範囲で設定しているのでアニメーションの経過時間が収束するようになっています。

<h2>まとめ

主な技術的ポイントは以上になります。
何か、誤っている点がございましたらご指摘いただけますと幸いです。

パーティクルアニメーションは値を少し変化させるだけで、
全く違った演出を表現できます。

↓下記はサンプルの背景色、奥いき等を変化させて制作してみました。

<a href="https://hisamikurita.github.io/perticle-rotation-02/dist/">● DEMO</a>

<p class="codepen" data-height="500" data-theme-id="dark" data-default-tab="result" data-user="hisamikurita" data-slug-hash="dyyJVQN" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Perticle Rotation #03">
  <span>See the Pen <a href="https://codepen.io/hisamikurita/pen/dyyJVQN">
  Perticle Rotation #03</a> by Hisami Kurita (<a href="https://codepen.io/hisamikurita">@hisamikurita</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

良ければ、<a href="https://codepen.io/hisamikurita/pen/dyyJVQN">CodePen</a>のコードを書き換えて遊んでみてください。

この記事をよんでパーティクルアニメーション、CSSに興味を持っていただけたら嬉しいです。

<h2>終わりに

こんな作品を週一(目標)で作って、<a href="https://codepen.io/hisamikurita">CodePen</a>に投稿してるので、良かったらフォローお願いします！

>参考
https://developer.mozilla.org/ja/docs/Web/CSS/animation-delay
https://sass-lang.com/documentation/modules/math