そろそろ雪が降る寒さになってきたので雪を降らせるエフェクト3選＋おまけ 

みなさんこんにちは。
来年はUIUXデザインとフロントエンド周りの知識を深めていきたいと思っていて毎日jsを書き始める活動をここ1週間継続しているわけですが←
そういや雪を降らせるエフェクトってどうやってやるのか知らないなあ、とふと思ったので、いくつか調べてまとめてみました。

# まずはシンプルに

HTML CSSがちょっとかければ作れる雪のエフェクトを紹介します。（js関係ない）

```HTML
!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="css/snowfall_one.css">
  <title>雪を降らせるサンプル其の1</title>
</head>
<body>
  <div class="snow">●</div>
</body>
</html>
```
はい、見ての通り、divタグ一個だけを使います。
ここは何も考えずに先に進みましょう。

```css

@charset "UTF-8";

body {
  background: black;
}


.snow {
  /*雪の色*/
  color: snow;
  /*雪の大きさ*/
  font-size: 18px;
  /*初期位置*/
  position: fixed;
  top: -5%;
  /*雪そのものを幅に適当な幅で降らせる*/
  text-shadow:
  5vw   -100px 2px,
  10vw  -400px 3px,
  20vw  -500px 4px,
  30vw  -580px 1px,
  39vw  -250px 2px,
  42vw  -340px 5px,
  56vw  -150px 2px,
  63vw  -180px 0,
  78vw  -220px 4px,
  86vw  -320px 9px,
  94vw  -170px 7px;

  /*アニメーションさせる*/
  animation: anim 5s linear infinite;
}

@keyframes anim {
  100% {
    color: transparent;
    top: 150%;
  }
}

```
cssはこんな感じです。
ものすごくざっくりと説明すると
①雪の大きさや背景色、初期位置を設定。

②text-shadowを使ってブラウザの幅いっぱいにdivタグの雪を広げます。-200pxとか書いている部分で、ベースとなる雪の粒からどれだけ上に雪の粒をずらすか、そのあとの部分では雪の部分に適当にぼかしを入れています。

あとはkeyframesを用いてアニメーションさせています。
100％になった時点で透明になるようにしています。

[デモはこちら](https://masanarih0ri.github.io/developmentbox/snowfall_one)

# 少しレベルをあげてみる

またしてもHTML CSSのみでかける例ですが、こんな感じでもかけます。

```HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="css/snowfall_two.css">
  <title>雪を降らせるサンプル其の2</title>
</head>
<body>
  <section id="snow">
    <div class="inner">
      <div class="snowflake1"></div>
      <div class="snowflake2"></div>
      <div class="snowflake3"></div>
      <div class="snowflake4"></div>
      <div class="snowflake5"></div>
      <div class="snowflake6"></div>
      <div class="snowflake7"></div>
      <div class="snowflake8"></div>
    </div>
  </section>
</body>
</html>

```

divタグの数が少し増えましたね。

さて、cssはというと

```css

@charset "UTF-8";


body {
  height: 1000px;
}

/*動かす前段階のアニメーション*/
section .inner div {
  animation-fill-mode: forwards;
  animation-iteration-count: infinite;
  animation-name: Drop;
  animation-timing-function: linear;
  opacity: 0;
  transform-origin: 0px 0px;
  height: 100%:
}

/*背景の設定*/
section#snow {
  background: #142744;
  overflow: hidden;
  width: 100%;
  height: 100%;
}

#snow .inner {
  height: 100%;
  width: 100%;
}
/*雪の設定*/
#snow .inner div {
  background: #fff;
  border-radius: 4px;
  display: block;
  height: 8px;
  position: absolute;
  width: 8px;
}

/*いくつかランダムに大きさを変える*/
#snow .inner div.snowflake1,
#snow .inner div.snowflake2,
#snow .inner div.snowflake5,
#snow .inner div.snowflake8 {
  background-size: 5px 6px;
}

/*雪をどの辺りに表示するか*/
.snowflake1 {
  animation-duration: 2.4s;
  left: 15%;
}

.snowflake2 {
  animation-delay: 0.3s;
  animation-duration: 2.7s;
  left: 19%;
}

.snowflake3 {
  animation-delay: 0.5s;
  animation-duration: 2.9s;
  left: 28%;
}

.snowflake4 {
  animation-delay: 0s;
  animation-duration: 2.6s;
  left: 38%;
}

.snowflake5 {
  animation-delay: 1s;
  animation-duration: 2.6s;
  left: 50%;
}

.snowflake6 {
  animation-delay: 1.2s;
  animation-duration: 2.2s;
  left: 60%;
}

.snowflake7 {
  animation-delay: 1.2s;
  animation-duration: 2.7s;
  left: 70%;
}

.snowflake8 {
  animation-delay: 1.4s;
  animation-duration: 2.9s;
  left: 85%;
}

/*アニメーションの設定*/
@keyframes Drop {
  0% {
    opacity: 0;
    transform: translateY(0px);
  }

  50% {
    opacity: 1;
    transform: translateY(50px);
  }

  100% {
    opacity: 0.3;
    transform: translateY(120px);
  }
}

```

こちらは最初の例の応用です。

違う部分は
divをいくつか使って（今回は8つ）、それの位置をposition: absolute;を使って適当に配置する。そしてアニメーションもanimation-delayプロパティとanimation-delayプロパティを利用して、時間差を作って雪を降らせています。
keyframesも少し複雑になっていますが、0% 50% 100%の時のcssを指定しているだけなので、そこまで難しくはないですね！
[デモはこちら](https://masanarih0ri.github.io/developmentbox/snowfall_two)

# 最後
長くなりましたが、最後です。（これが一番コード的に長いんだけど...）
3Dで雪を降らせよう！というものがあったので、そちらを紹介します。
three.jsを使っているのですが、three.jsについては割愛。
three.jsを詳しく知りたい人は[こちら](https://ics.media/entry/14771)で。

```HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="css/snowfall_three.css">
  <script
  src="https://code.jquery.com/jquery-1.12.4.min.js"
  integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
  crossorigin="anonymous"></script>
  <script src="js/canvas.js"></script>
  <script src="js/snow.js"></script>
  <script src="js/snowfall_three.js"></script>
  <title>雪を降らせるサンプル其の3</title>
</head>
<body>

</body>
</html>

```
HTMLはシンプル。あとでjsでdivタグを追加します。
ここで読み込んでいるcanvas.jsとsnow.js、そしてsnowfall_three.jsで３Dエフェクトを作ります。
※canvas.jsとsnow.jsの内容は[こちら](https://github.com/sebleedelisle/live-coding-presentations/tree/master/2011/JSSnow/js)

```css
@charset "UTF-8";

body {
  background: #000;
  color: #fff;
}

/*jsで表示する部分*/
#snow_canvas {
  left: 0;
  position: fixed;
  top: 0;
  z-index: 99999999999999;
}

```
とりあえず背景色を黒にしておきました。
snow_canvasというidがHTMLにないんですけど...というのはちょっと気になるかもしれませんがあとで分かるので無視して進みましょう。

```js
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;

//three.jsを利用するために変数をいくつか設定
var container;
var particle;
var camera;
var scene;
var renderer;

var mouseX = 0;
var mouseY = 0;
var snownum = 500;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

var particles = [];
var particleImage = new Image();
//雪の画像を設定
particleImage.src = 'http://efu.sakura.ne.jp/web/snow3/img/ParticleSmoke.png';

function init() {
  container = document.createElement('div');
  //自動で作成されるdiv要素にid追加
  container.id = 'snow_canvas';
  // body要素の中にdivを追加
  document.body.appendChild(container);
  camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 );
  //カメラの位置を設定
  camera.position.z = 1000;

  scene = new THREE.Scene();
  scene.add(camera);

  renderer = new THREE.CanvasRenderer();
  //rendererのサイズを画面サイズにする
  renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
  var material = new THREE.ParticleBasicMaterial( { map: new THREE.Texture(particleImage) } );

  for (var i = 0; i < snownum; i++) {
    particle = new Particle3D( material);
    particle.position.x = Math.random() * 2500 - 1000;
    particle.position.y = Math.random() * 2500 - 1800;
    particle.position.z = Math.random() * 2500 - 1050;
    particle.scale.x = particle.scale.y =  1;
    scene.add( particle );

    particles.push(particle);
  }

  container.appendChild( renderer.domElement );
  container.addEventListener( 'mousemove', onDocumentMouseMove, false );
  container.addEventListener( 'touchstart', onDocumentTouchStart, false );
  container.addEventListener( 'touchmove', onDocumentTouchMove, false );
  setInterval( loop, 1000 / 60 );

}

function onDocumentMouseMove( event ) {
  mouseX = event.clientX - windowHalfX;
  mouseY = event.clientY - windowHalfY;
}

function onDocumentTouchStart( event ) {
  if ( event.touches.length == 1 ) {
    event.preventDefault();
    mouseX = event.touches[ 0 ].pageX - windowHalfX;
    mouseY = event.touches[ 0 ].pageY - windowHalfY;
  }
}

function onDocumentTouchMove( event ) {
  if ( event.touches.length == 1 ) {
    event.preventDefault();
    mouseX = event.touches[ 0 ].pageX - windowHalfX;
    mouseY = event.touches[ 0 ].pageY - windowHalfY;
  }
}

function loop() {

  for(var i = 0; i<particles.length; i++)
  {
    var particle = particles[i];
    particle.updatePhysics();

    with(particle.position)
    {
      if(y<-1000) y+=2000;
      if(x>1000) x-=2000;
      else if(x<-1000) x+=2000;
      if(z>1000) z-=2000;
      else if(z<-1000) z+=2000;
    }
  }

  camera.position.x += ( mouseX - camera.position.x ) * 0.05;
  camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
  camera.lookAt(scene.position);

  renderer.render( scene, camera );


}
//initの呼び出し
if (window.addEventListener) {
  window.addEventListener("load", init, false);
} else if (window.attachEvent) {
  window.attachEvent("onload", init);
} else  {
  window.onload = init;
}

```

こんな感じでjsを書くと、いい感じに3D空間上で雪が降ってくれます。
・シーン、カメラ、レンダラーを作る。
・動かす物体を描画する
・アニメーションを使って動かす

という手順でthree.jsを動かしています。
まあ、コードの意味がわからなくても、コピペすれば動きますので、それで楽しむのもありですね。
[デモはこちら](https://masanarih0ri.github.io/developmentbox/snowfall_three)
# おまけ
ちなみに。jQueryのプラグインでjQuery-Snowfallというものを使うと、瞬殺で雪を降らせることができるみたいなので、リンクを貼り付けておきますね^^
[jQuery-Snowfall](http://www.north-geek.com/entry/jquery-snow)

以上です！意外とたくさんやり方あるんですね。
調べてみると楽しかったです。