La idea
Medimos dónde está el cursor dentro de la tarjeta como un valor de
-0.5 a 0.5 (izquierda/derecha y arriba/abajo). Ese valor lo convertimos
en grados de rotación. Como el contenedor tiene perspective, la
rotación se ve en 3D en vez de plana.
const px = (e.clientX - r.left) / r.width - .5;
const py = (e.clientY - r.top) / r.height - .5;
card.style.transform =
`rotateY(${px * 22}deg) rotateX(${-py * 22}deg)`;
Ese 22 es el slider de arriba: muévelo y mira el número cambiar aquí.
Paso 1 · El HTML
<div class="escena"> <div class="tarjeta">3D</div> </div>
Paso 2 · El CSS
La perspective va en el padre. La tarjeta necesita
transform-style: preserve-3d para que sus hijos también vivan en 3D.
.escena{ perspective:800px; }
.tarjeta{
transform-style:preserve-3d;
transition:transform .2s ease;
}
.tarjeta span{ transform:translateZ(36px); }
Paso 3 · El JavaScript
escena.addEventListener('mousemove', e => {
const r = escena.getBoundingClientRect();
const px = (e.clientX - r.left) / r.width - .5;
const py = (e.clientY - r.top) / r.height - .5;
card.style.transform = `rotateY(${px*22}deg) rotateX(${-py*22}deg)`;
});
escena.addEventListener('mouseleave', () => card.style.transform = '');
El detalle que suma
El translateZ en un elemento interno (como el texto) hace que
“flote” sobre la tarjeta: al inclinar, se mueve distinto al fondo y el efecto de
profundidad se vuelve convincente. Es parallax, el mismo truco de la mascota.
Listo 🎉
Con perspective + dos rotaciones tienes una tarjeta viva. Prueba subir la intensidad al máximo para un efecto más dramático.