【JavaScript】桜舞うプログラム

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>桜舞うプログラム</title>
  <style>
    body {
      margin: 0;
      background: linear-gradient(to bottom, #FFEEFF, #ffffff);
      height: 100vh;
      position: relative;
    }
    .sakura {
      position: fixed;
      pointer-events: none;
      /* transform-origin を中心に設定 */
      transform-origin: center center;
    }
    /* 花びらが落下しながら左右にゆらゆら揺れるアニメーション */
    @keyframes fall {
      0% {
        transform: translateX(0) translateY(-100px) rotate(0deg);
        opacity: 1;
      }
      25% {
        transform: translateX(50px) translateY(25vh) rotate(90deg);
      }
      50% {
        transform: translateX(0) translateY(50vh) rotate(180deg);
      }
      75% {
        transform: translateX(-50px) translateY(75vh) rotate(270deg);
      }
      100% {
        transform: translateX(0) translateY(110vh) rotate(360deg);
        opacity: 0;
      }
    }
  </style>
</head>
<body>
  <script>
    function createSakura() {
      const xmlns = "http://www.w3.org/2000/svg";
      const svg = document.createElementNS(xmlns, "svg");
      svg.setAttribute("viewBox", "0 0 40 40");
      svg.setAttribute("class", "sakura");

      // ランダムなサイズ設定(scale 0.5~1.25倍、40pxを基準)
      const scale = Math.random() * 0.75 + 0.5;
      const size = 40 * scale;
      svg.style.width = `${size}px`;
      svg.style.height = `${size}px`;

      // 横方向の初期位置(画面全体からランダムに)
      svg.style.left = Math.random() * window.innerWidth + "px";
      // 垂直方向は画面外上部から開始
      svg.style.top = "-50px";

      // SVG内にパス要素を作成
      const path = document.createElementNS(xmlns, "path");
      path.setAttribute("d", "M20.1,11.6l-2.5,3.1-2.5-3.1c-2.2,1.8-3.7,6-3.7,10.7s6.2,11.8,6.2,11.8c0,0,6.2-5.3,6.2-11.8s-1.5-8.9-3.7-10.7Z");
      path.setAttribute("fill", "#FFC3E7");

      svg.appendChild(path);

      // ランダムなアニメーション設定(5~10秒、開始遅延もランダム)
      const duration = Math.random() * 5 + 5;
      const delay = Math.random() * -20;
      svg.style.animation = `fall ${duration}s linear ${delay}s infinite`;

      document.body.appendChild(svg);

      // アニメーション終了後に削除してパフォーマンス対策
      setTimeout(() => { svg.remove(); }, duration * 1000);
    }

    function generateSakura() {
      setInterval(createSakura, 150);
    }

    generateSakura();
  </script>
</body>
</html>

CSS によるスタイル設定とアニメーション

背景と全体レイアウト

body {
  margin: 0;
  background: linear-gradient(to bottom, #FFEEFF, #ffffff);
  height: 100vh;
  position: relative;
}
  • 背景: ページ全体の背景には、ピンクのグラデーションを設定します。
  • レイアウト: height: 100vh により、画面全体を使い、position: relative により内部要素(花びら)の配置の基準にします。

花びら(.sakura クラス)のスタイル

.sakura {
  position: fixed;
  pointer-events: none;
  transform-origin: center center;
}
  • 位置指定: position: fixed を使用して、画面上で固定された位置に表示。これにより、スクロールなどの影響を受けずにアニメーションが継続します。
  • ポインター無効: pointer-events: none; でマウスイベントを無効にします。
  • 変形の基準: transform-origin: center center; により、花びらの回転や移動の基準を中央に設定。

アニメーション (keyframes)

@keyframes fall {
  0% {
    transform: translateX(0) translateY(-100px) rotate(0deg);
    opacity: 1;
  }
  25% {
    transform: translateX(50px) translateY(25vh) rotate(90deg);
  }
  50% {
    transform: translateX(0) translateY(50vh) rotate(180deg);
  }
  75% {
    transform: translateX(-50px) translateY(75vh) rotate(270deg);
  }
  100% {
    transform: translateX(0) translateY(110vh) rotate(360deg);
    opacity: 0;
  }
}
  • 初期状態: 上部(-100px)から開始し、透明度は1(完全に表示)です。
  • 途中の動き:
    • 25% で右に50px移動し、画面下部の 25vh まで移動、同時に90度回転。
    • 50% で中央に戻り、50vh の位置に到達し、180度回転。
    • 75% では、左へ50px移動し、75vh に到達、270度回転。
  • 終了状態: 100% で元の横位置に戻りながら、110vh の位置に到達し、360度回転。透明度は0になり、フェードアウトします。
  • この一連の動きが、花びらが「落下しながら左右に揺れる」効果を生み出しています。

JavaScript による動的生成

JavaScript 部分では、一定間隔で花びらを生成し、各花びらにランダムなパラメーターを設定しています。

SVG を用いた花びらの生成

function createSakura() {
  const xmlns = "http://www.w3.org/2000/svg";
  const svg = document.createElementNS(xmlns, "svg");
  svg.setAttribute("viewBox", "0 0 40 40");
  svg.setAttribute("class", "sakura");
  • SVG 要素の作成:
    インライン SVG を使用することで、clip-path ではなく、正しいスケーリングと座標系が適用されます。
    viewBox="0 0 40 40" により、花びらのパスが 40px を基準に描画されます。

サイズ・位置・アニメーションのランダム設定

  // ランダムなサイズ設定(scale 0.5~1.25倍、40pxを基準)
  const scale = Math.random() * 0.75 + 0.5;
  const size = 40 * scale;
  svg.style.width = `${size}px`;
  svg.style.height = `${size}px`;

  // 横方向の初期位置(画面全体からランダムに)
  svg.style.left = Math.random() * window.innerWidth + "px";
  // 垂直方向は画面外上部から開始
  svg.style.top = "-50px";
  • サイズ: ランダムなスケールで各花びらの大きさを変化させ、自然なバリエーションを実現しています。
  • 位置: 横位置は画面全体からランダムに選ばれ、縦位置は画面外上部から開始することで、徐々に下へ落ちるアニメーションが始まります。

SVG パスの設定とアニメーションの適用

  // SVG内にパス要素を作成
  const path = document.createElementNS(xmlns, "path");
  path.setAttribute("d", "M20.1,11.6l-2.5,3.1-2.5-3.1c-2.2,1.8-3.7,6-3.7,10.7s6.2,11.8,6.2,11.8c0,0,6.2-5.3,6.2-11.8s-1.5-8.9-3.7-10.7Z");
  path.setAttribute("fill", "#FFC3E7");

  svg.appendChild(path);
  • パスの定義:
    事前に用意された桜の花びらの形状(SVG の path データ)を設定しています。
  • 塗りの色: 桜らしい淡いピンク(#FFC3E7)で塗り、柔らかい印象を与えています。

アニメーションのランダム適用とパフォーマンス対策

  // ランダムなアニメーション設定(5~10秒、開始遅延もランダム)
  const duration = Math.random() * 5 + 5;
  const delay = Math.random() * -20;
  svg.style.animation = `fall ${duration}s linear ${delay}s infinite`;

  document.body.appendChild(svg);

  // アニメーション終了後に削除してパフォーマンス対策
  setTimeout(() => { svg.remove(); }, duration * 1000);
  • ランダムなアニメーション:
    各花びらは 5~10 秒間のランダムな持続時間でアニメーションが実行され、開始遅延もランダムに設定されています。
  • パフォーマンス対策:
    アニメーションが終了したら SVG 要素を削除することで、メモリ消費の増大やパフォーマンス低下を防ぎます。

花びらの生成ループ

function generateSakura() {
  setInterval(createSakura, 150);
}
generateSakura();
  • 定期生成:
    setInterval を用いて、150ミリ秒ごとに createSakura 関数を呼び出し、画面に次々と花びらを追加していきます。
  • このループにより、常に新しい花びらが舞うような効果が生み出されています。

まとめ

今回のプログラムでは、以下の技術を組み合わせて実装しています。

  • HTML:ページの基本構造とコンテンツの配置。
  • CSS:背景、花びらのスタイル、及び複雑なアニメーション(落下、左右の揺れ、回転)を定義。
  • SVG:花びらの形状を正確に再現するために、インライン SVG と viewBox を活用。
  • JavaScript:花びらの動的生成、ランダムなサイズ・位置・アニメーションのパラメーター設定、及び生成後の削除によるパフォーマンス最適化。

この仕組みにより、桜の花びらが風に揺れながら、自然な動きで舞うアニメーションが実現されています。コードをカスタマイズすることで、色や動き、生成間隔などを変更できるため、より好みに合わせた桜舞うエフェクトに仕上げることが可能です。