预览

用例和功能

磁性工具提示是一个丰富的 UI 组件,可以平滑地跟随用户的光标。

设计和用户体验要点

  1. 动画舒适度

    使用缓动函数和“requestAnimationFrame”的线性插值(Lerp)实现平滑运动而不卡顿。

  2. 视觉层次

    通过分层“box-shadow”和“backdrop-filter”,我们创建了一种三维效果,就好像元素漂浮在屏幕上一样。

  3. 不要打断互动

    工具提示本身设计有“pointer-events: none”,以免干扰用户的悬停操作。

如何定制

实现代码

<div class="magnetic-tooltip-container">

<button class="magnetic-target" data-tooltip="🚀 新しいアップデートが利用可能です">

  Hover Me

</button>

<button class="magnetic-target" data-tooltip="✨ プレミアム機能を見る">

  Explore

</button>

<div class="magnetic-tooltip"></div>

</div>



<style>
.magnetic-tooltip-container {

  display: flex;

  gap: 2rem;

  justify-content: center;

  align-items: center;

  min-height: 400px;

  background: #000000;

  background-image: radial-gradient(circle at 50% 50%, #1a1a2e 0%, #000000 100%);

  border-radius: 1rem;

  position: relative;

  font-family: 'Inter', system-ui, sans-serif;

}



.magnetic-target {

  padding: 1rem 2.5rem;

  font-size: 1.125rem;

  font-weight: 600;

  color: #ffffff;

  background: linear-gradient(135deg, #3b82f6, #8b5cf6);

  border: 1px solid rgba(255, 255, 255, 0.1);

  border-radius: 9999px;

  cursor: pointer;

  box-shadow: 0 10px 30px -10px rgba(139, 92, 246, 0.5);

  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.3s ease, filter 0.3s ease;

}



.magnetic-target:hover {

  box-shadow: 0 20px 40px -10px rgba(139, 92, 246, 0.7);

  filter: brightness(1.1);

}



.magnetic-tooltip {

  position: fixed;

  top: 0;

  left: 0;

  pointer-events: none;

  padding: 0.75rem 1.25rem;

  background: rgba(15, 23, 42, 0.85);

  backdrop-filter: blur(16px);

  -webkit-backdrop-filter: blur(16px);

  border: 1px solid rgba(255, 255, 255, 0.15);

  border-radius: 0.75rem;

  color: #f8fafc;

  font-size: 0.875rem;

  font-weight: 500;

  white-space: nowrap;

  box-shadow: 

    0 4px 6px -1px rgba(0, 0, 0, 0.1), 

    0 24px 38px 3px rgba(0, 0, 0, 0.14),

    inset 0 1px 0 rgba(255, 255, 255, 0.1);

  opacity: 0;

  transform: translate(-50%, -100%) scale(0.9) translateY(10px);

  transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);

  z-index: 9999;

}



.magnetic-tooltip.visible {

  opacity: 1;

  transform: translate(-50%, -100%) scale(1) translateY(-15px);

}

</style>



<script>

(function initMagneticTooltip() {

  const targets = document.querySelectorAll('.magnetic-target');

  const tooltip = document.querySelector('.magnetic-tooltip');



  if(!tooltip) return;



  let mouseX = 0;

  let mouseY = 0;

  let tooltipX = 0;

  let tooltipY = 0;

  let isHovered = false;

  let animationFrameId;



  const speed = 0.15;



  function animate() {

    if (isHovered) {

      tooltipX += (mouseX - tooltipX) * speed;

      tooltipY += (mouseY - tooltipY) * speed;

      tooltip.style.left = tooltipX + 'px';

      tooltip.style.top = tooltipY + 'px';

      animationFrameId = requestAnimationFrame(animate);

    }

  }



  targets.forEach(function(target) {

    target.addEventListener('mouseenter', function(e) {

      isHovered = true;

      tooltip.textContent = target.getAttribute('data-tooltip');

      tooltip.classList.add('visible');

      

      mouseX = e.clientX;

      mouseY = e.clientY;

      tooltipX = mouseX;

      tooltipY = mouseY;

      tooltip.style.left = tooltipX + 'px';

      tooltip.style.top = tooltipY + 'px';

      

      if (animationFrameId) cancelAnimationFrame(animationFrameId);

      animate();

    });



    target.addEventListener('mousemove', function(e) {

      mouseX = e.clientX;

      mouseY = e.clientY;



      // Magnetic pull effect on the button itself

      const rect = target.getBoundingClientRect();

      const centerX = rect.left + rect.width / 2;

      const centerY = rect.top + rect.height / 2;

      const deltaX = (mouseX - centerX) * 0.3;

      const deltaY = (mouseY - centerY) * 0.3;

      target.style.transform = 'translate(' + deltaX + 'px, ' + deltaY + 'px) scale(1.05)';

    });



    target.addEventListener('mouseleave', function() {

      isHovered = false;

      tooltip.classList.remove('visible');

      target.style.transform = ''; // reset button position

      if (animationFrameId) cancelAnimationFrame(animationFrameId);

    });

  });

})();

</script>

浏览器兼容性状态

边缘:是的

*最新的主流浏览器都支持“backdrop-filter”属性。 Safari 使用“-webkit-”前缀。