Skip to content

Efectos de cursor ​

Los efectos de cursor son muy populares en portafolios, agencias creativas y sitios de producto. Bien hechos, dan una sensación premium; mal hechos, hacen que el sitio sea difícil de usar. Aquí verás cómo hacerlos fluidos y responsables.

Concepto: seguir al mouse sin trabarse ​

Todos los efectos de esta sección siguen el mismo patrón:

  1. Escuchar pointermove y guardar la posición del mouse en variables (sin tocar el DOM).
  2. Actualizar el DOM en un bucle requestAnimationFrame, como mucho una vez por fotograma.
  3. Mover con transform: translate(), nunca con top/left.

Para que un elemento siga al mouse "con retraso" elegante se usa interpolación lineal (lerp): en cada fotograma, el elemento recorre un porcentaje de la distancia que le falta.

js
// Con factor 0.15 recorre el 15 % de la distancia en cada fotograma:
// rápido cuando está lejos, suave al llegar
x += (mouseX - x) * 0.15;
y += (mouseY - y) * 0.15;
el.style.transform = `translate(${x}px, ${y}px)`;

Responsabilidad con el cursor

  • Nunca ocultes el cursor nativo en táctiles: usa @media (hover: hover) and (pointer: fine) para aplicar el efecto sólo con mouse real.
  • El elemento decorativo debe tener pointer-events: none para no bloquear los clics.
  • Respeta prefers-reduced-motion: elimina el retraso o desactiva el efecto.
  • En sitios de cliente "serios" (bancos, gobierno, salud), mejor no usarlos.

Cursor personalizado ​

Un punto que sigue al mouse exactamente y un anillo que lo sigue con suavidad. Sobre enlaces y botones, el anillo crece; al hacer clic, se encoge.

Cursor con punto y anillo

Cómo funciona:

  • El punto se mueve directamente en pointermove (sin retraso).
  • El anillo se actualiza en el bucle requestAnimationFrame con lerp (--suavidad en el CSS).
  • e.target.closest('a, button') detecta si el mouse está sobre algo clicable y añade la clase .sobre-enlace al body. El CSS cambia la variable --anillo y la transición hace el resto.
  • mix-blend-mode: difference invierte los colores debajo del anillo, como en muchos portafolios de diseño.
  • El cursor nativo se oculta sólo si el dispositivo tiene mouse y después del primer movimiento (clase .cursor-activo).

Estela del cursor (trail) ​

Una cadena de círculos que persiguen al mouse, cada uno más pequeño y transparente que el anterior. Funciona también con el dedo en táctiles.

Estela que sigue al cursor

El truco está en que cada círculo persigue al anterior, no al mouse:

js
let x = mx, y = my;                     // el primero persigue al mouse
puntos.forEach((p, i) => {
  p.x += (x - p.x) * SEGUIMIENTO;
  p.y += (y - p.y) * SEGUIMIENTO;
  const escala = 1 - i / TOTAL;
  p.el.style.transform = `translate(${p.x}px, ${p.y}px) scale(${escala})`;
  x = p.x; y = p.y;                     // el siguiente persigue a este
});

Cambia TOTAL y SEGUIMIENTO para estelas más largas o más "elásticas".

Spotlight (luz que sigue al mouse) ​

Una luz suave en el fondo y tarjetas cuyo interior y borde se iluminan donde está el cursor. Es el efecto que popularizaron sitios como Vercel o Linear.

Spotlight en fondo y tarjetas

Aquí JavaScript sólo actualiza variables CSS; los degradados los dibuja el CSS:

css
body {
  background:
    radial-gradient(280px circle at var(--x, 50%) var(--y, 30%), rgb(139 92 246 / .35), transparent 70%),
    #050816;
}
js
addEventListener('pointermove', (e) => {
  document.body.style.setProperty('--x', e.clientX + 'px');
  document.body.style.setProperty('--y', e.clientY + 'px');
});

El borde iluminado de las tarjetas usa una técnica de máscara: un ::after con padding: 1px y dos máscaras combinadas con mask-composite: exclude, que eliminan el contenido y dejan visible sólo el anillo del padding, es decir, el borde.

Efecto decorativo = cero riesgo

El spotlight no oculta el cursor ni cambia cómo se interactúa con la página: si el JS no carga, todo sigue funcionando y sólo se pierde el brillo. Es la opción más segura para sitios de clientes.

Ejercicios ​

  1. Haz que el anillo del cursor muestre el texto "Ver" cuando esté sobre una imagen.
  2. Cambia la estela para que cada círculo tenga un color distinto del arcoíris (hsl(i * 20 ...)).
  3. Añade al spotlight una cuarta tarjeta y comprueba que el efecto funciona sin tocar el JS.
Ver solución del ejercicio 2
js
puntos.forEach((p, i) => {
  p.el.style.background = `hsl(${i * 20} 90% 60%)`;
});

Resumen ​

  • Patrón base: guardar la posición en pointermove y pintar en requestAnimationFrame.
  • Lerp (x += (destino - x) * factor) da movimiento suave sin librerías.
  • Mueve con transform, usa pointer-events: none y aplica el efecto sólo con (hover: hover) and (pointer: fine).
  • Actualizar variables CSS desde JS (spotlight) es lo más limpio y eficiente.

Academia Web — aprende, copia y construye.