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.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Create a Mouse‑Responsive 3D Card Tilt Effect with CSS & JavaScript

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.

3D tilt effect demo
3D tilt effect demo

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.

preview image
preview 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.

rotation direction illustration
rotation direction illustration
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.

corner rotation map
corner rotation map

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

and 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

final demo screenshot
final demo screenshot
frontendanimationJavaScriptCSS3D effectmouse interaction
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.