3D 倾斜容器组件(鼠标跟随倾斜卡片,倾角/视距/高光可调)
3D 倾斜容器组件:鼠标位置实时驱动卡片 rotateX/rotateY 倾斜,内层元素按 translateZ 深度错位形成景深,倾角、视距、高光扫过可调,自研 JS 平滑插值零依赖。
效果演示(真实可交互)
🖱 在卡片上移动鼠标:卡片 3D 倾斜,内层元素按深度错位
完整代码
实现思路分三步:鼠标在容器内的相对位置归一化到 [-0.5, 0.5];把该值乘以最大倾角得到目标 rotateX/rotateY;用指数平滑(lerp)逐帧逼近目标,避免抖动。内层元素通过 translateZ 分布在不同深度,倾斜时天然产生错位景深。
<div class="scene" id="scene">
<div class="card" id="card">
<div class="layer layer--bg"></div>
<div class="layer layer--icon" style="--dz:48px">🧊</div>
<div class="layer layer--title" style="--dz:34px">3D 倾斜容器</div>
</div>
</div>
.scene { perspective: 900px; } /* 视距决定 3D 强度 */
.card {
width: 280px; height: 330px;
transform-style: preserve-3d; /* 层与层保持空间关系 */
will-change: transform;
}
.layer {
position: absolute; inset: 0;
border-radius: 20px;
transform: translateZ(var(--dz, 0px)); /* 每层不同深度 */
}
.layer--bg {
background: linear-gradient(160deg, #2b3a67, #141b33);
border: 1px solid rgba(255, 255, 255, .14);
}
const scene = document.getElementById('scene');
const card = document.getElementById('card');
const state = { tx: 0, ty: 0, rx: 0, ry: 0, running: false };
const MAX = 16; // 最大倾角(度)
scene.addEventListener('pointermove', e => {
const r = scene.getBoundingClientRect();
state.tx = (e.clientX - r.left) / r.width - 0.5; // -0.5 ~ 0.5
state.ty = (e.clientY - r.top) / r.height - 0.5;
if (!state.running) { state.running = true; requestAnimationFrame(loop); }
});
function loop() {
const tx = -state.ty * 2 * MAX;
const ty = state.tx * 2 * MAX;
state.rx += (tx - state.rx) * 0.12; // 指数平滑,0.12 为跟随速度
state.ry += (ty - state.ry) * 0.12;
card.style.transform = `rotateX(${state.rx.toFixed(2)}deg) rotateY(${state.ry.toFixed(2)}deg)`;
if (Math.abs(tx - state.rx) > 0.05 || Math.abs(ty - state.ry) > 0.05) {
requestAnimationFrame(loop);
} else { state.running = false; }
}
参数说明
| 参数 | 位置 | 说明 |
|---|---|---|
| 最大倾角 | MAX 常量 | 演示中 4-32° 可调,越大倾斜越明显 |
| 视距 | perspective | 500-1400px,影响景深强度 |
| 跟随速度 | 平滑系数 0.12 | 越大跟手越快,越小越丝滑 |
| 层深度 | --dz | 每层 translateZ 值,控制景深错位幅度 |
| 高光扫过 | --gx/--gy | 径向渐变跟随鼠标位置,营造光泽感 |
兼容性与性能
- 仅使用
transform与 CSS 变量,全部由 GPU 合成,60fps 无压力 - 指数平滑写法避免了对每帧做三角函数运算,开销可忽略
- 鼠标离开后自动回正(目标归零),回正动画复用同一循环,代码精简
- Chrome / Safari / Firefox / Edge 全支持;iOS Safari 建议保留
-webkit-transform-style: preserve-3d - 触屏设备无鼠标事件,可用
pointermove(演示即用 Pointer Events)兼顾触控与鼠标 - 内容层为普通元素,读屏器可正常朗读,无障碍友好
常见问题
Q: 倾斜很生硬、像开关不像跟随? 平滑系数过小或过大都会造成此感。建议 0.08-0.2 之间;同时确认 will-change: transform 已设置,避免每帧触发重排。
Q: 内层元素没有景深、全部贴在一起? 检查三点:容器必须 transform-style: preserve-3d;每层要有不同的 translateZ;容器本身被倾斜(rotateX/rotateY)——三者缺一,层间深度都不可见。
Q: 移动端触摸时卡片乱转? 指针事件在触摸时会同时派发 mouse 事件导致抖动。可改用 pointermove 并配合 touch-action: none(演示已采用该写法),或仅在 pointerType === 'mouse' 时响应。
Q: 可以商用吗? 可以。本组件为粤喵自研原创代码,免费商用无需署名,颜色、层数、倾角均可自由定制。
许可与来源
- 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
- 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
- 首次发布:2026-09-01 · 最近更新:2026-09-01
- 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
- 纠错:联系页面 / min@cactus.asia,2 个工作日内核实处理
常见问题
这个组件可以商用吗?
可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。
浏览器兼容性如何?
支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。
怎么修改动画参数?
直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。