Create a Mouse‑Responsive 3D Card Tilt Effect with CSS & JavaScript
This tutorial explains how to build a 3D card tilt effect that follows the mouse cursor by stacking HTML elements, applying CSS perspective and rotation, calculating rotation angles from mouse offsets, and updating CSS variables with JavaScript, complete with code snippets and a live demo.
When building a website, you may want a panel that tilts in response to mouse movement, creating a 3D effect similar to the Viteconf homepage.
Below is a step‑by‑step implementation.
Stacking Elements
First build the basic markup.
<div class="card">
<img src="xxx" />
</div>Then add the required CSS.
body {
margin: 0;
border-radius: 16px;
min-height: 100vh;
display: grid;
place-content: center;
background: #a2a77b;
}
img {
border-radius: inherit;
height: 100%;
width: 100%;
}
.card {
display: block;
border-radius: inherit;
height: 370px;
overflow: hidden;
}The grid layout centers the card and displays the image.
Principle Analysis
Rotation Direction
The mouse point acts like a force that rotates the card around the X and Y axes. In CSS, positive angles rotate counter‑clockwise when looking along the axis direction.
z‑axis should stay fixed; otherwise the image would spin like a roulette wheel.
Depending on the mouse position in the four corners, the card rotates in different directions, as shown below.
Rotation Angle Calculation
Define a small adjustment range, e.g. const RANGE = [-5, 5]. The angle for each axis is computed from the mouse offset relative to the image size:
mouseX / imageWidth * (RANGE[1] - RANGE[0]) + RANGE[0] offsetXand offsetY from the mousemove event provide the needed distances.
card.addEventListener('mousemove', (e) => {
const { offsetX, offsetY } = e;
console.log(compute(offsetX, offsetY));
});Code Implementation
Set CSS variables for rotation.
.card {
transition: transform 0.1s;
transform: perspective(400px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
}Perspective controls the depth; smaller values increase the effect.
JavaScript calculates the angles and updates the variables.
const RANGE = [-5, 5];
const getRotate = (value, max) => value / max * (RANGE[1] - RANGE[0]) + RANGE[0];
const offsetWidth = card.offsetWidth;
const offsetHeight = card.offsetHeight;
card.addEventListener('mousemove', (e) => {
const { offsetX, offsetY } = e;
const rx = -getRotate(offsetY, offsetHeight);
const ry = getRotate(offsetX, offsetWidth);
card.style.setProperty('--rx', `${rx}deg`);
card.style.setProperty('--ry', `${ry}deg`);
});Open the demo to see the effect in action:
https://code.juejin.cn/pen/7340484096105627657
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
