
Animar un contenedor al pasar el ratón por encima usando perspectiva y transformación

He estado trabajando en un sitio web en el que se muestran imágenes grandes al usuario. En lugar de crear un efecto de caja de luz típico (una animación de acercamiento con una superposición negra) para estas imágenes grandes, decidí intentar hacer algo más interactivo y divertido. Terminé codificando un contenedor de imágenes que se inclina cuando el usuario mueve el cursor del mouse sobre él.
Aquí está la versión final:
Este efecto se logra mediante CSS y JavaScript. Pensé en hacer un pequeño tutorial explicando cómo funciona cada parte para que puedas reproducirla o ampliarla fácilmente.
Recomiendo leer las entradas del almanaque para obtener perspectiva y transformarse antes de comenzar. Nos referiremos a estas propiedades a través de la publicación y es una buena idea estar familiarizados con ellas.
Vayamos al grano.
Configuración
Primero, necesitamos un contenedor con otro elemento interior. El contenedor ayudará con la perspectiva.
div div/div/div
Para fines de demostración, centremos la tarjeta exactamente en el medio de la pantalla:
body { /* Full screen width and height */ width: 100%; min-height: 100vh; /* Centers the container in the middle of the screen */ display: flex; justify-content: center; align-items: center; margin: 0; background-color: rgb(220, 220, 220);}#container { /* This will come into play later */ perspective: 40px;}#inner { width: 20em; height: 18em; background-color: white;}
Esto nos da una tarjeta blanca que se coloca directamente en el centro de un fondo gris claro. Tenga en cuenta que hemos establecido la perspectiva de que #container
no 40px
hace nada en este momento porque no hemos creado ninguna transformación. Esto se manejará más adelante en JavaScript.
Comencemos a crear secuencias de comandos
Aquí está el resumen de lo que estamos haciendo:
var container = document.getElementById('container');var inner = document.getElementById('inner'); var onMouseEnterHandler = function(event) { update(event);};var onMouseLeaveHandler = function() { inner.style = "";};var onMouseMoveHandler = function(event) { if (isTimeToUpdate()) { update(event); }};container.onmouseenter = onMouseEnterHandler;container.onmouseleave = onMouseLeaveHandler;container.onmousemove = onMouseMoveHandler;
Y esto es lo que todas esas cosas están haciendo (o harán):
- Funciones de controlador: estas funciones manejan los eventos a medida que ocurren. Queremos decidir qué sucede cuando el cursor entra, se mueve y sale del contenedor, por lo que cada uno de ellos tiene un controlador.
- Función de actualización: aún no hemos codificado esto, pero su objetivo será actualizar la rotación 3D de nuestro
#inner
div. - Función Hora de actualizar: esta es otra función que aún no hemos codificado, pero volverá
true
cuando se requiera una actualización. Esta es una forma de reducir el número de llamadas a laupdate()
función y mejorar el rendimiento de nuestro script. - Evento: este es un objeto JavaScript que describe el evento que ocurrió.
El código anterior:
- Actualice la rotación 3D del div interno tan pronto como el mouse ingrese al contenedor.
- Actualice la rotación 3D del div interno cuando llegue el momento apropiado mientras el mouse se mueve sobre el contenedor.
- Restablezca el estilo del div interno cuando el mouse salga del contenedor.
¿Es hora de actualizar?
Agreguemos la función que decide cuándo actualizar la rotación 3D del #inner
div.
var counter = 0;var updateRate = 10;var isTimeToUpdate = function() { return counter++ % updateRate === 0;};
Cuando counter
llegue al updateRate
, se realizará una actualización.
En este punto, puedes intentar reemplazar la update
función por a console.log()
y jugar con updateRate
para ver cómo funciona todo en conjunto.
El ratón
El siguiente es el objeto del mouse. Esta es un poco más compleja que las otras secciones. Aún así, no es tan difícil de entender, pero el código puede parecer intimidante, especialmente si eres nuevo en JavaScript.
// Initvar container = document.getElementById('container');var inner = document.getElementById('inner');// Mouse var mouse = { _x: 0, _y: 0, x: 0, y: 0, updatePosition: function(event) { var e = event || window.event; this.x = e.clientX - this._x; this.y = (e.clientY - this._y) * -1; }, setOrigin: function(e) { this._x = e.offsetLeft + Math.floor(e.offsetWidth/2); this._y = e.offsetTop + Math.floor(e.offsetHeight/2); }, show: function() { return '(' + this.x + ', ' + this.y + ')'; }}// Track the mouse position relative to the center of the container.mouse.setOrigin(container);
Nuevamente, analicemos esto juntos.
show()
:Muestra la posición actual del mouse (si desea realizar alguna depuración en la consola del navegador).setOrigin(e)
: Establece las coordenadas(0,0)
de nuestromouse
objeto en el centro del elemento (e
).updatePosition()
: Actualiza la posición actual de nuestromouse
objeto, en relación con(0,0)
.
La última línea de código mouse.setOrigin(container)
ajusta las coordenadas (0,0)
de nuestro mouse
objeto al centro de nuestro contenedor. He aquí un ejemplo que lo ilustra.
La idea detrás de todo esto es agregar más rotación a nuestro #inner
div a medida que mueves el mouse más lejos del centro del contenedor.
Actualizar estilos en la posición del mouse
Aquí está nuestra función de actualización:
var update = function(event) { mouse.updatePosition(event); updateTransformStyle( (mouse.y / inner.offsetHeight/2).toFixed(2), (mouse.x / inner.offsetWidth/2).toFixed(2) );};var updateTransformStyle = function(x, y) { var style = "rotateX(" + x + "deg) rotateY(" + y + "deg)"; inner.style.transform = style; inner.style.webkitTransform = style; inner.style.mozTransform = style; inner.style.msTransform = style; inner.style.oTransform = style;};
update()
:Actualiza la posición del mouse y actualiza el estilo del#inner
div.updateTransformStyle()
: actualiza el estilo de cada prefijo de proveedor.
¿Terminamos?
¡Será mejor que hagamos algunas pruebas! Parece que obtenemos un cambio de perspectiva cuando el cursor del mouse entra y sale de la tarjeta, pero no es tan fluido como podría ser:
¡Correcto! Le dijimos que actualizara la rotación de nuestro #inner
div cada vez que counter
llegue al updateRate
. Esto produce una transición torpe entre actualizaciones.
¿Cómo solucionamos eso? Transiciones CSS.
Agregar transiciones
#inner { transition: transform 0.5s;}
Estos son números arbitrarios. Puedes jugar con la perspectiva y transformar valores para que el efecto sea más o menos dramático como mejor te parezca.
Tenga en cuenta que cambiar el tamaño de la página causará algunos problemas porque la posición del contenedor cambia en la página. La solución es volver a centrar su mouse
objeto en su container
después de cambiar el tamaño de la página.
Terminando
¡Hemos terminado! Ahora tenemos un contenedor para hacer un elemento un poco más interactivo. La demostración al comienzo de esta publicación usa una imagen dentro del contenedor, pero se puede usar para otras cosas además de las imágenes, incluidos formularios, modales o casi cualquier otro contenido que coloque en el contenedor. ¡Vaya a experimentar!
Deja una respuesta