2分で読める

CSSで美しい気泡アニメーションを作る

純粋なCSSとJavaScriptで実装する、浮遊する気泡エフェクトのチュートリアル

CSSで美しい気泡アニメーションを作る

ウェブサイトに動きのあるアクセントを加えたいとき、気泡(バブル)アニメーションは非常に効果的です。この記事では、純粋なCSSとJavaScriptを使って美しい気泡エフェクトを実装する方法を解説します。

完成イメージ

水中を浮遊するような気泡が、画面下から上へとゆっくり浮かび上がるエフェクトを作ります。各気泡はランダムなサイズ、速度、横方向の揺れを持ちます。

Step 1: HTML構造

まず、気泡を配置するコンテナを用意します。

<div class="bubble-container">
  <!-- 気泡は JavaScript で動的に生成します -->
</div>

Step 2: 基本的なCSS

コンテナと気泡の基本スタイルを定義します。

.bubble-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: hidden;
  z-index: -1;
}

.bubble {
  position: absolute;
  bottom: -100px;
  background: radial-gradient(
    circle at 30% 30%,
    rgba(255, 255, 255, 0.8),
    rgba(255, 255, 255, 0.2) 50%,
    transparent 70%
  );
  border-radius: 50%;
  opacity: 0.6;
  animation: rise linear infinite;
}

ヒント

pointer-events: none を設定することで、気泡がクリックやホバーの邪魔をしないようにします。

Step 3: 浮上アニメーション

気泡が下から上へ浮かび上がるアニメーションを定義します。

@keyframes rise {
  0% {
    transform: translateY(0) translateX(0);
    opacity: 0;
  }
  10% {
    opacity: 0.6;
  }
  90% {
    opacity: 0.6;
  }
  100% {
    transform: translateY(-110vh) translateX(var(--drift, 0px));
    opacity: 0;
  }
}

Step 4: 横方向の揺れ

より自然な動きを出すために、横方向の揺れを追加します。

@keyframes wobble {
  0%, 100% {
    transform: translateX(0);
  }
  25% {
    transform: translateX(-20px);
  }
  75% {
    transform: translateX(20px);
  }
}

.bubble {
  /* 既存のスタイルに追加 */
  animation: 
    rise linear infinite,
    wobble ease-in-out infinite;
}

Step 5: JavaScript で動的に生成

ランダムなサイズと速度の気泡を生成します。

function createBubble() {
  const bubble = document.createElement('div');
  bubble.className = 'bubble';
  
  // ランダムなサイズ (10px ~ 60px)
  const size = Math.random() * 50 + 10;
  bubble.style.width = `${size}px`;
  bubble.style.height = `${size}px`;
  
  // ランダムな水平位置
  bubble.style.left = `${Math.random() * 100}%`;
  
  // ランダムな浮上速度 (8秒 ~ 15秒)
  const duration = Math.random() * 7 + 8;
  bubble.style.animationDuration = `${duration}s, ${duration / 2}s`;
  
  // ランダムな横方向のドリフト
  const drift = (Math.random() - 0.5) * 100;
  bubble.style.setProperty('--drift', `${drift}px`);
  
  // ランダムな遅延
  bubble.style.animationDelay = `${Math.random() * 5}s`;
  
  return bubble;
}

function initBubbles(count = 15) {
  const container = document.querySelector('.bubble-container');
  
  for (let i = 0; i < count; i++) {
    const bubble = createBubble();
    container.appendChild(bubble);
  }
}

// ページ読み込み時に実行
document.addEventListener('DOMContentLoaded', () => {
  initBubbles(15);
});

Step 6: 完全なコード

すべてをまとめた完全なコードです。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>気泡アニメーション</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      min-height: 100vh;
      background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
    }

    .bubble-container {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      pointer-events: none;
      overflow: hidden;
      z-index: 1;
    }

    .bubble {
      position: absolute;
      bottom: -100px;
      background: radial-gradient(
        circle at 30% 30%,
        rgba(255, 255, 255, 0.8),
        rgba(255, 255, 255, 0.3) 40%,
        rgba(255, 255, 255, 0.1) 60%,
        transparent 70%
      );
      border: 1px solid rgba(255, 255, 255, 0.2);
      border-radius: 50%;
      box-shadow: 
        inset 0 -5px 20px rgba(255, 255, 255, 0.1),
        0 0 20px rgba(255, 255, 255, 0.1);
      animation: 
        rise linear infinite,
        wobble ease-in-out infinite;
    }

    @keyframes rise {
      0% {
        transform: translateY(0) scale(1);
        opacity: 0;
      }
      10% {
        opacity: 0.6;
      }
      90% {
        opacity: 0.4;
      }
      100% {
        transform: translateY(-110vh) translateX(var(--drift, 0px)) scale(0.8);
        opacity: 0;
      }
    }

    @keyframes wobble {
      0%, 100% {
        margin-left: 0;
      }
      25% {
        margin-left: -15px;
      }
      75% {
        margin-left: 15px;
      }
    }
  </style>
</head>
<body>
  <div class="bubble-container"></div>

  <script>
    function createBubble() {
      const bubble = document.createElement('div');
      bubble.className = 'bubble';
      
      const size = Math.random() * 50 + 10;
      bubble.style.width = `${size}px`;
      bubble.style.height = `${size}px`;
      bubble.style.left = `${Math.random() * 100}%`;
      
      const duration = Math.random() * 7 + 8;
      bubble.style.animationDuration = `${duration}s, ${duration / 2}s`;
      
      const drift = (Math.random() - 0.5) * 100;
      bubble.style.setProperty('--drift', `${drift}px`);
      bubble.style.animationDelay = `${Math.random() * 5}s`;
      
      return bubble;
    }

    function initBubbles(count = 15) {
      const container = document.querySelector('.bubble-container');
      for (let i = 0; i < count; i++) {
        container.appendChild(createBubble());
      }
    }

    document.addEventListener('DOMContentLoaded', () => initBubbles(15));
  </script>
</body>
</html>

カスタマイズのヒント

色付きの気泡

.bubble.blue {
  background: radial-gradient(
    circle at 30% 30%,
    rgba(100, 200, 255, 0.8),
    rgba(100, 200, 255, 0.2) 50%,
    transparent 70%
  );
}

.bubble.pink {
  background: radial-gradient(
    circle at 30% 30%,
    rgba(255, 150, 200, 0.8),
    rgba(255, 150, 200, 0.2) 50%,
    transparent 70%
  );
}

パフォーマンス最適化

注意

多数の気泡を表示する場合は、will-change: transform を追加してGPUアクセラレーションを有効にしましょう。ただし、使いすぎるとメモリ消費が増えるので注意が必要です。

.bubble {
  will-change: transform, opacity;
}

クリックで気泡を追加

インタラクティブな要素として、クリックで気泡を追加する機能も実装できます。

document.addEventListener('click', (e) => {
  const bubble = createBubble();
  bubble.style.left = `${e.clientX}px`;
  bubble.style.bottom = `${window.innerHeight - e.clientY}px`;
  document.querySelector('.bubble-container').appendChild(bubble);
  
  // アニメーション終了後に削除
  setTimeout(() => bubble.remove(), 15000);
});

まとめ

CSSアニメーションとJavaScriptを組み合わせることで、美しい気泡エフェクトを実装できました。このテクニックは以下のような場面で活用できます:

  • ランディングページの背景装飾
  • 水族館や海をテーマにしたサイト
  • ローディング画面のアクセント
  • インタラクティブなユーザー体験の演出

ぜひ自分のプロジェクトでカスタマイズして使ってみてください。

関連する記事