鼠标悬浮进卡片有波纹扩散效果

把鼠标划进来
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>鼠标坐标水波纹</title>
<style>
  /* 卡片基本样式 */
  .ripple-card{
    position:relative;
    overflow:hidden;          /* 关键:裁剪波纹 */
    width:240px;
    height:120px;
    line-height:120px;
    text-align:center;
    background:#49B1F5;
    color:#fff;
    font-size:18px;
    border-radius:12px;
    cursor:pointer;
    user-select:none;
  }

  /* 波纹本体 */
  .ripple-wave{
    position:absolute;
    border-radius:50%;
    background:rgba(255,255,255,.4);
    transform:scale(0);
    animation:ripple .6s linear;
    pointer-events:none;
  }

  @keyframes ripple{
    to{
      transform:scale(4);   /* 足够大即可覆盖 */
      opacity:0;
    }
  }
</style>
</head>
<body style="display:flex;align-items:center;justify-content:center;height:100vh;background:#f2f4f8;">

  <div class="ripple-card">把鼠标划进来</div>

<script>
  // 统一处理 .ripple-card 内的鼠标事件
  document.querySelectorAll('.ripple-card').forEach(card=>{
    card.addEventListener('mousemove', createRipple);
  });

  function createRipple(e){
    // 避免连续触发
    if(this.dataset.rippling) return;
    this.dataset.rippling = '1';

    const rect = this.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    // 计算最大半径(确保能覆盖整个卡片)
    const maxR = Math.hypot(
      Math.max(x, rect.width - x),
      Math.max(y, rect.height - y)
    );

    const wave = document.createElement('span');
    wave.className = 'ripple-wave';
    wave.style.left = x + 'px';
    wave.style.top  = y + 'px';
    wave.style.width  = wave.style.height = maxR * 2 + 'px';
    wave.style.marginLeft = wave.style.marginTop = -maxR + 'px';

    this.appendChild(wave);

    // 动画结束后清理
    wave.addEventListener('animationend', ()=>{
      wave.remove();
      delete this.dataset.rippling;
    });
  }
</script>
</body>
</html>

如果你只希望划入/划出时触发动画,则可以:

划入 & 划出
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>划入 / 划出 一次波纹</title>
<style>
  .card{
    position:relative;
    overflow:hidden;
    width:240px;
    height:120px;
    line-height:120px;
    text-align:center;
    background:#49B1F5;
    color:#fff;
    border-radius:12px;
    cursor:pointer;
    user-select:none;
  }

  /* 划入波纹 */
  .wave-in,
  .wave-out{
    position:absolute;
    border-radius:50%;
    transform:scale(0);
    pointer-events:none;
  }
  .wave-in{
    background:rgba(255,255,255,.4);
    animation:ripple-in .6s forwards;
  }
  .wave-out{
    background:rgba(0,0,0,.15);   /* 暗色回弹 */
    animation:ripple-out .4s forwards;
  }

  @keyframes ripple-in{
    to{ transform:scale(4); opacity:0; }
  }
  @keyframes ripple-out{
    to{ transform:scale(3); opacity:0; }
  }
</style>
</head>
<body style="display:flex;align-items:center;justify-content:center;height:100vh;background:#f2f4f8;">
  <div class="card">划入 & 划出</div>

<script>
  const card = document.querySelector('.card');

  function addWave(cls, x, y){
    const rect = card.getBoundingClientRect();
    const maxR = Math.hypot(
      Math.max(x, rect.width - x),
      Math.max(y, rect.height - y)
    );

    const wave = document.createElement('span');
    wave.className = cls;
    wave.style.left = x + 'px';
    wave.style.top  = y + 'px';
    wave.style.width = wave.style.height = maxR * 2 + 'px';
    wave.style.marginLeft = wave.style.marginTop = -maxR + 'px';

    card.appendChild(wave);
    wave.addEventListener('animationend', ()=> wave.remove());
  }

  card.addEventListener('mouseenter', e => {
    const rect = card.getBoundingClientRect();
    addWave('wave-in', e.clientX - rect.left, e.clientY - rect.top);
  });

  card.addEventListener('mouseleave', e => {
    const rect = card.getBoundingClientRect();
    addWave('wave-out', e.clientX - rect.left, e.clientY - rect.top);
  });
</script>
</body>
</html>

还有鼠标移入使图片模糊的(不知道为什么这里显示不了。。。把代码复制一份在自己浏览器上看)

把鼠标放上来
HTML

<style>

  /* 卡片外壳 */
  .card3{
    position:relative;
    width:300px;
    height:200px;
    border-radius:16px;
    overflow:hidden;
    cursor:pointer;
    box-shadow:0 8px 24px rgba(0,0,0,.15);
  }
  /* 背景层 */
  .bg{
    width:100%;
    height:100%;
    background:url('https://picsum.photos/600/400?random=3') center/cover;
  }
  /* 模糊遮罩层(默认看不见) */
  .blur-mask{
    position:absolute;
    inset:0;
    background:url('https://picsum.photos/600/400?random=3') center/cover;
    filter:blur(12px);
    /* 通过 mask 裁剪为圆形,径向渐变中心由 JS 实时更新 */
    mask-image:radial-gradient(circle at 50% 50%, #000 0%, transparent 0%);
    -webkit-mask-image:radial-gradient(circle at 50% 50%, #000 0%, transparent 0%);
    mask-size:100% 100%;
    -webkit-mask-size:100% 100%;
    transition:mask-position 0s, -webkit-mask-position 0s; /* 位置立即生效 */
  }
  /* 文字 */
  .txt{
    position:absolute;
    inset:0;
    display:flex;
    align-items:center;
    justify-content:center;
    color:#fff;
    font-size:20px;
    font-weight:600;
    text-shadow:0 1px 4px rgba(0,0,0,.4);
    pointer-events:none;
  }
</style>



  <div class="card3">
    <div class="bg"></div>
    <div class="blur-mask"></div>
    <div class="txt">把鼠标放上来</div>
  </div>

<script>
  const card   = document.querySelector('.card3');
  const blurM  = document.querySelector('.blur-mask');

  /* 圆形半径动画帧 */
  let animId = null;

  /* 统一更新 mask 中心与半径 */
  function updateMask(x, y, radius){
    const mask = `radial-gradient(circle at ${x}px ${y}px, #000 ${radius}%, transparent ${radius}%)`;
    blurM.style.maskImage = mask;
    blurM.style.webkitMaskImage = mask;
  }

  /* mouseenter:0 → 100 半径 */
  card.addEventListener('mouseenter', e=>{
    const rect = card.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    let r = 0;
    const step = ()=>{
      r += 2;                     // 每帧增长 2 %
      updateMask(x, y, r);
      if(r < 100) animId = requestAnimationFrame(step);
    };
    step();
  });

  /* mouseleave:100 → 0 半径 */
  card.addEventListener('mouseleave', e=>{
    const rect = card.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    cancelAnimationFrame(animId);
    let r = 100;
    const step = ()=>{
      r -= 3;
      updateMask(x, y, Math.max(r,0));
      if(r > 0) animId = requestAnimationFrame(step);
    };
    step();
  });
</script>

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注