/animation-inner-ripple
Article

动画 - 涟漪

L
Lawrence
|Reading time

动画 - 涟漪

本教程展示通过 CSS 创建涟漪动画

**实现思路**

  1. 按钮点击时,在点击位置创建涟漪元素
  2. 涟漪从中心向外扩散并淡出
  3. 动画结束后移除涟漪元素

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      margin: 0;
      background: #1a1a1a;
    }

    .ripple-btn {
      position: relative;
      padding: 16px 32px;
      font-size: 18px;
      font-weight: 600;
      color: #fff;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      border: none;
      border-radius: 8px;
      cursor: pointer;
      overflow: hidden;
      transition: transform 0.2s, box-shadow 0.2s;
    }

    .ripple-btn:hover {
      transform: translateY(-2px);
      box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
    }

    .ripple-btn:active {
      transform: translateY(0);
    }

    .ripple {
      position: absolute;
      border-radius: 50%;
      background: rgba(255, 255, 255, 0.6);
      transform: scale(0);
      animation: ripple-animation 0.6s ease-out;
      pointer-events: none;
    }

    @keyframes ripple-animation {
      to {
        transform: scale(4);
        opacity: 0;
      }
    }
  </style>
</head>
<body>
  <button class="ripple-btn">Click Me!</button>

  <script>
    const btn = document.querySelector('.ripple-btn');

    btn.addEventListener('click', function(e) {
      const ripple = document.createElement('span');
      ripple.classList.add('ripple');

      const rect = btn.getBoundingClientRect();
      const size = Math.max(rect.width, rect.height);
      const x = e.clientX - rect.left - size / 2;
      const y = e.clientY - rect.top - size / 2;

      ripple.style.width = ripple.style.height = size + 'px';
      ripple.style.left = x + 'px';
      ripple.style.top = y + 'px';

      btn.appendChild(ripple);

      ripple.addEventListener('animationend', function() {
        ripple.remove();
      });
    });
  </script>
</body>
</html>

Read-only

**关键点**

  • overflow: hidden 防止涟漪溢出按钮
  • 使用 getBoundingClientRect() 计算按钮位置
  • 涟漪大小取按钮宽高的最大值,确保覆盖角落
  • 动画结束后通过 animationend 事件清理 DOM