本文详解如何将 JavaScript 3D 倾斜效果(tilt effect)正确绑定到 CSS Grid 容器内所有子元素,解决仅首个元素响应 mousemove 的常见问题,并提供基于相对坐标计算的健壮实现方案。
本文详解如何将 JavaScript 3D 倾斜效果(tilt effect)正确绑定到 CSS Grid 容器内所有子元素,解决仅首个元素响应 mousemove 的常见问题,并提供基于相对坐标计算的健壮实现方案。
在使用 CSS Grid 构建卡片布局并希望为每个网格项(如 .card > div)添加独立的 3D 倾斜交互效果时,一个典型误区是仅用 document.querySelector() 获取首个匹配元素,导致事件监听器只挂载到第一个子元素上。要让每个网格项都具备响应式倾斜能力,必须批量选取所有目标元素并为每个元素单独绑定事件监听器,同时确保旋转计算基于该元素自身的坐标系(而非整个视口),才能实现精准、互不干扰的交互体验。
使用 document.querySelectorAll('.card > div') 获取全部目标元素,再通过 forEach() 为每个元素注册 mousemove 事件:
const cards = document.querySelectorAll('.card > div');cards.forEach(card => {card.addEventListener('mousemove', cardMove);});function cardMove(e) {const box = e.currentTarget; // 当前触发事件的具体 div 元素const rect = box.getBoundingClientRect(); // 获取其相对于视口的位置和尺寸const midX = box.offsetWidth / 2;const midY = box.offsetHeight / 2;// 计算鼠标相对于该元素左上角的偏移量(关键!)const x = e.clientX - rect.left;const y = e.clientY - rect.top;// 根据偏移比例计算旋转角度(±20° 范围更自然)const rotX = (((x - midX) / midX) * 20).toFixed(2);const rotY = ((-1 * (y - midY) / midY) * 20).toFixed(2);// 应用透视 + 双轴旋转(注意:perspective 值不宜过大,200px~500px 更适合小卡片)box.style.transform = `perspective(200px) rotateX(${rotY}deg) rotateY(${rotX}deg)`;}
card.addEventListener('mouseleave', () => {card.style.transform = 'perspective(200px) rotateX(0deg) rotateY(0deg)';});
通过以上改造,每个 .card > div 都能独立响应鼠标移动,产生符合物理直觉的 3D 倾斜效果——无论网格排列方式如何变化,交互始终精准、高效且可维护。