插件窝 干货文章 如何用JavaScript和CSS实现网页触摸涟漪动画效果?

如何用JavaScript和CSS实现网页触摸涟漪动画效果?

ripple style button transform 1004    来源:    2025-03-25

实现网页触摸涟漪动画效果

触摸涟漪效果是现代UI设计中常见的交互反馈,可以通过JavaScript和CSS实现。下面我将介绍几种实现方法。

方法一:纯CSS实现(有限场景)

<button class="ripple-button">点击我</button>

<style>
.ripple-button {
  position: relative;
  overflow: hidden;
  padding: 12px 24px;
  border: none;
  background-color: #6200ee;
  color: white;
  cursor: pointer;
  border-radius: 4px;
}

.ripple-button:after {
  content: "";
  display: block;
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  pointer-events: none;
  background-image: radial-gradient(circle, #fff 10%, transparent 10.01%);
  background-repeat: no-repeat;
  background-position: 50%;
  transform: scale(10, 10);
  opacity: 0;
  transition: transform .5s, opacity 1s;
}

.ripple-button:active:after {
  transform: scale(0, 0);
  opacity: .3;
  transition: 0s;
}
</style>

限制:这种方法只能在按钮激活时显示效果,无法精确定位触摸点。

方法二:JavaScript + CSS实现(推荐)

<button class="ripple-btn">点击我</button>

<style>
.ripple-btn {
  position: relative;
  overflow: hidden;
  padding: 12px 24px;
  border: none;
  background-color: #6200ee;
  color: white;
  cursor: pointer;
  border-radius: 4px;
}

.ripple {
  position: absolute;
  border-radius: 50%;
  background-color: rgba(255, 255, 255, 0.7);
  transform: scale(0);
  animation: ripple 600ms linear;
  pointer-events: none;
}

@keyframes ripple {
  to {
    transform: scale(4);
    opacity: 0;
  }
}
</style>

<script>
document.querySelectorAll('.ripple-btn').forEach(button => {
  button.addEventListener('click', function(e) {
    // 获取点击位置相对于按钮的位置
    const rect = button.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    // 创建涟漪元素
    const ripple = document.createElement('span');
    ripple.classList.add('ripple');
    ripple.style.left = `${x}px`;
    ripple.style.top = `${y}px`;

    // 添加到按钮中
    this.appendChild(ripple);

    // 动画结束后移除元素
    setTimeout(() => {
      ripple.remove();
    }, 600);
  });
});
</script>

方法三:使用CSS变量优化

<button class="ripple-btn-advanced">高级涟漪效果</button>

<style>
.ripple-btn-advanced {
  position: relative;
  overflow: hidden;
  padding: 12px 24px;
  border: none;
  background-color: #6200ee;
  color: white;
  cursor: pointer;
  border-radius: 4px;
  --ripple-x: 0;
  --ripple-y: 0;
}

.ripple-btn-advanced::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: radial-gradient(
    circle at var(--ripple-x) var(--ripple-y),
    rgba(255, 255, 255, 0.8) 0%,
    rgba(255, 255, 255, 0) 70%
  );
  transform: scale(0);
  opacity: 0;
  pointer-events: none;
}

.ripple-btn-advanced.animate::after {
  animation: ripple-animation 0.6s ease-out;
}

@keyframes ripple-animation {
  0% {
    transform: scale(0);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 0;
  }
}
</style>

<script>
document.querySelectorAll('.ripple-btn-advanced').forEach(button => {
  button.addEventListener('click', function(e) {
    const rect = button.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    // 设置CSS变量
    this.style.setProperty('--ripple-x', `${x}px`);
    this.style.setProperty('--ripple-y', `${y}px`);

    // 添加动画类
    this.classList.add('animate');

    // 动画结束后移除类
    setTimeout(() => {
      this.classList.remove('animate');
    }, 600);
  });
});
</script>

方法四:封装为可重用组件

class RippleEffect {
  constructor(element, options = {}) {
    this.element = element;
    this.options = {
      color: 'rgba(255, 255, 255, 0.7)',
      duration: 600,
      ...options
    };

    this.init();
  }

  init() {
    this.element.style.position = 'relative';
    this.element.style.overflow = 'hidden';

    this.element.addEventListener('click', this.createRipple.bind(this));
  }

  createRipple(e) {
    const rect = this.element.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    const diameter = Math.max(rect.width, rect.height);

    const ripple = document.createElement('span');
    ripple.style.position = 'absolute';
    ripple.style.width = ripple.style.height = `${diameter}px`;
    ripple.style.left = `${x - diameter / 2}px`;
    ripple.style.top = `${y - diameter / 2}px`;
    ripple.style.borderRadius = '50%';
    ripple.style.backgroundColor = this.options.color;
    ripple.style.transform = 'scale(0)';
    ripple.style.transition = `transform ${this.options.duration}ms ease-out, opacity ${this.options.duration}ms ease-out`;
    ripple.style.pointerEvents = 'none';

    this.element.appendChild(ripple);

    setTimeout(() => {
      ripple.style.transform = 'scale(2)';
      ripple.style.opacity = '0';
    }, 10);

    setTimeout(() => {
      ripple.remove();
    }, this.options.duration);
  }
}

// 使用示例
document.querySelectorAll('[data-ripple]').forEach(el => {
  new RippleEffect(el, {
    color: 'rgba(255, 255, 255, 0.5)',
    duration: 800
  });
});

注意事项

  1. 性能优化:避免在滚动容器中使用大量涟漪效果
  2. 无障碍访问:确保效果不会干扰键盘导航
  3. 移动端适配:同时处理clicktouch事件
  4. 浏览器兼容性:如果需要支持旧浏览器,可能需要添加前缀

以上方法可以根据项目需求选择使用,方法二和方法三是最常用的实现方式。