CSS animation で遊び倒す - Particle  3D-


CSS animation day25 となりました。
本日は、3D表現を用いた、Particle をやります。

なお、2D版も作りましたので、よろしければ[前回](https://qiita.com/duka/items/498d1c72cd46abea8392) の記事をご参照ください。



#1. 完成版
![ダウンロード (65).gif](https://qiita-image-store.s3.amazonaws.com/0/232715/6d5df259-4969-708c-a605-8e777a129b78.gif)

<p class="codepen" data-height="489" data-theme-id="0" data-default-tab="html,result" data-user="hiroyaiizuka" data-slug-hash="aXRVJg" style="height: 489px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Particle Sphere">
  <span>See the Pen <a href="https://codepen.io/hiroyaiizuka/pen/aXRVJg/">
  Particle Sphere</a> by hiroya iizuka (<a href="https://codepen.io/hiroyaiizuka">@hiroyaiizuka</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

#2. なぜか？

[codrops](https://tympanus.net/codrops/2017/12/12/3d-particle-explorations/) によると、3D Particle の表現は、ページをローディングする待ち時間のアニメーションに使うと、効果的です。

確かに3D Particleは綺麗ですし、ランダムに動くのを見てても飽きないですし、楽しいですよね。いくらでも待てそうな気がします。

UX を向上させるために、こうした技術は、役に立ちそうですね！

#3. 参考文献
[Particle Orb CSS](https://codepen.io/natewiley/pen/GgONKy)
[CSS 3D Particles](https://codepen.io/timohausmann/pen/zxBnd)

#4. 分解してみる

❶. 
まずは、マークアップをします。
前回と同様のコードを書きます。

```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="css/styles.css" />
  </head>

  <body>
    <div class="container">
      <div class="particle-wrap"></div>
      <div class="particle"></div>
      <div class="particle"></div>
                ・
　　　　　　　　　 ・
　　　　　　　　　 ・
　　　　　　　　　×　100 
   </div>
  </body>
</html>
```

```styles.scss
body {
  margin: 0px;
  padding: 0px;
  background: #000;
  overflow: hidden;
}

.container {
  width: 100%;
  height: 100vh;
  position: relative;
}


.particle {
  background: #fff;
  border-radius: 50%;
  height: 20px;
  width: 20px;
  position: absolute;

  @for $i from 1 through 100 {
    &:nth-child(#{$i}) {
      transform: translate(random(100) * 1vw, random(100) * 1vh);
    }
  }
}
```

<img width="1079" alt="スクリーンショット 2019-02-15 15.04.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/232715/aad4c348-0b75-1c13-3efd-2a2f214962cb.png">


<br/>
❷. 
ここから、3D 表現をつけていきたいところですが、知識の復習をしましょう。


CSS で3D 表現をする時に、以下の3つが大事です。　
>
1: transform-style: preserve 3d 
2: perspective
3: rotate



__transform-style: preserve-3d__

[transform-style](https://developer.mozilla.org/ja/docs/Web/CSS/transform-style) は、要素の子要素を、3D 空間に配置する(preserve-3d)か、平面に配置する(flat)かを決めます。立体的に見せたい要素の親要素に、transform-style を指定しましょう。


__perspective__

遠近感を出す手法です。値が小さいほど、広角レンズのように歪みが大きくなります。

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="html,result" data-user="ykob" data-slug-hash="bNvLLa" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="css transform rotate/perspective test">
  <span>See the Pen <a href="https://codepen.io/ykob/pen/bNvLLa/">
  css transform rotate/perspective test</a> by yoichi kobayashi (<a href="https://codepen.io/ykob">@ykob</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


perspectiveも、立体的に見せたい要素の親要素に、指定しましょう。


__rotate__

[StarWars](https://qiita.com/duka/items/c971ca0749a8bcb5c617) の以前の記事でrotate Xの解説をしました。また、[こちら](https://qiita.com/KazuyoshiGoto/items/72905b62c9a56807d892) のQiita 記事も大変わかりやすくまとまっております。

___

❸. 

では、これから 3D を作りますが、ここで質問です！
3D座標空間で、中心から、ある一定距離に、点をランダムに配置すると、どんな形になるでしょうか？

・・・

そうです、球になりますね！
コードを書いて実験しましょう。


```styles.scss
body {
  margin: 0px;
  padding: 0px;
  background: #000;
  overflow: hidden;
}

.container {
  width: 100%;
  height: 100vh;
  position: relative;
  transform-style: preserve-3d;
  perspective: 1000px;
}

.particle {
  position: absolute;
  margin: 50vh 50vw;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #fff;
}

@for $i from 1 through 100 {
  .particle:nth-child(#{$i}) {
    animation: rotate#{$i} 4s infinite;
  }

  @keyframes rotate#{$i} {
    100% {
      transform: rotateX((random(360) * 1deg)) rotateY((random(360) * 1deg))
                 rotateZ((random(360) * 1deg)) translateZ(200px);
    }
  }
}
```

![ダウンロード (61).gif](https://qiita-image-store.s3.amazonaws.com/0/232715/3cbdb201-a289-6aba-08c0-80f46da20971.gif)


球になりました！
ポイントというか、はまったところですが

animation: `rotate#{$i}`
keyframes `rotate#{$i}`というように、
for文の中でアニメーションを設定し、particle要素の一つ一つにアニメーションをつけなければなりません。いつものように、animation: rotate としてしまうと、アニメーションがうまく動かず、3時間くらいハマるので、気をつけましょう。

では、色を変え、keyframes をいじります。

```styles.scss
 @for $i from 1 through 100 {
   .particle:nth-child(#{$i}) {
     animation: rotate#{$i} 4s infinite;
     background: hsl(random(360), 75%, 75%);
     width: random(15) * 1 + px;
     height: random(15) * 1 + px;
  }

  @keyframes rotate#{$i} {
    30% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translateZ(300px);
    }
    50% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translateZ(100px);
    }
    70% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translateZ(130px);
    }
    90% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translateZ(50px);
    }
    100% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translateZ(600px);
    }
  }
}
```

![ダウンロード (62).gif](https://qiita-image-store.s3.amazonaws.com/0/232715/edf8a6ba-d42b-5af3-a147-7cd406e49ae6.gif)


いい感じです。
translateの値をいじると、こういう動きのほか、もっと別の表現もできます。

```styles.scss

  @keyframes rotate#{$i} {
    30% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translateZ(300px);
    }
    50% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translate(300px, 600px);
    }
    70% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translate(400px, 200px);
    }
    90% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translateZ(50px);
    }
    100% {
      transform: rotateY((random(360) * 1deg)) rotateZ((random(360) * 1deg))
        rotateX((random(360) * 1deg)) translateZ(600px);
    }
  }
```
![ダウンロード (63).gif](https://qiita-image-store.s3.amazonaws.com/0/232715/d468a287-ca1c-899d-5209-5bd5e305dbfe.gif)

様々な表現ができて楽しいですね。

❹.
では最後に、ちょっとおまけです。
下のGIF をご覧ください。

![ダウンロード (64).gif](https://qiita-image-store.s3.amazonaws.com/0/232715/e94b7b92-04a9-5598-72cd-610bd661b88a.gif)

これは、HTMLで入れ子の構造を持った親要素にアニメーションをつけて回転させたものですが、ご覧の通り、入れ子の子要素(赤い点)にもアニメーションが適応されます。

この特性を生かして、球体が、地球のようにぐるぐる回転する表現をつけましょう。

```index.html
    <div class="container">
      <div class="wrapper">
        <div class="particle"></div>
        <div class="particle"></div>
        <div class="particle"></div>
                ・
　　　　　　　　　 ・
　　　　　　　　　 ・
　　　　　　　　　×　100 
      </div>  
    </div>
```


```styles.scss
.wrapper {
  will-change: animation;
  animation: moveAround 4s infinite;
  transform-style: preserve-3d;
}

@keyframes moveAround {
  100% {
    transform: rotateY(360deg);
  }
}
```

![ダウンロード (65).gif](https://qiita-image-store.s3.amazonaws.com/0/232715/0992ec66-07d5-b0a4-a19c-3c0e3289052d.gif)


無事、Particle が、全体的に、横に回転するようになりました。
こういう、綺麗なParticle動画が、CSS だけでできるなんて、素晴らしいですね。

では、また明日〜！