SnippetUI

Tooltip Magnetic Động

Chú giải công cụ hoạt hình mờ dần tinh vi theo dõi chuyển động của con trỏ trên phần tử một cách mượt mà.

HTMLCSSJavaScript

Xem trước

Trường hợp sử dụng và tính năng

Chú giải công cụ từ tính là một thành phần giao diện người dùng phong phú, di chuyển mượt mà theo con trỏ của người dùng.

  • Theo dõi mượt mà: Thêm độ trễ (nới lỏng) cho chuyển động của chuột để tạo ấn tượng tự nhiên và tinh tế.
  • Thiết kế theo phong cách thủy tinh: Sự kết hợp giữa làm mờ hậu cảnh (bộ lọc phông nền) và đường viền mờ tạo nên vẻ đẹp tương lai.
  • Phản hồi trực quan: Hoàn hảo cho các nút kêu gọi hành động, thẻ và các yếu tố khác mà bạn muốn thu hút sự chú ý.

Điểm thiết kế và UX

  1. Sự thoải mái của hoạt hình Nội suy tuyến tính (Lerp) sử dụng chức năng nới lỏng và requestAnimationFrame đạt được chuyển động mượt mà mà không bị giật hình.
  2. Phân cấp trực quan Bằng cách xếp lớp box-shadowbackdrop-filter, chúng tôi tạo ra hiệu ứng ba chiều như thể các phần tử đang nổi trên màn hình.
  3. Không làm gián đoạn sự tương tác Bản thân chú giải công cụ được thiết kế với pointer-events: none để không can thiệp vào thao tác di chuột của người dùng.

Cách tùy chỉnh

  • Điều chỉnh tốc độ sau: Bạn có thể điều chỉnh tốc độ theo dõi bằng cách thay đổi giá trị của const speed = 0,15; trong JavaScript (gần 1, nhanh hơn).
  • Thay đổi màu chủ đề: Vui lòng thay đổi màu nền của tuyến tính-gradient.magnetic-tooltip của .magnetic-target trong CSS để phù hợp với chủ đề dự án.
  • Độ lệch vị trí: Bạn có thể thay đổi khoảng cách từ con trỏ đến chú giải công cụ bằng cách điều chỉnh giá trị của transform: ... TranslateY(-15px); trong .magnetic-tooltip.visible.

Mã triển khai

<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>

Trạng thái tương thích với trình duyệt

  • Chrome: Được hỗ trợ
  • Firefox: Được hỗ trợ
  • Safari: Được hỗ trợ
  • Cạnh: Có

*Thuộc tính backdrop-filter được hỗ trợ bởi các trình duyệt chính mới nhất. Safari sử dụng tiền tố -webkit-.