He estado trabajando en un sitio web en el que se muestran imágenes grandes al usuario. En lugar de crear un efecto típico de caja de luz (una animación de zoom 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:
Vea el Pen MrLopq de Mihai (@MihaiIonescu) en CodePen.
Este efecto se logra mediante CSS y JavaScript. Pensé que haría 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 transformación antes de comenzar. Vamos a referirnos a estas propiedades a través de la publicación y es una buena idea estar familiarizado con ellas.
Pongámonos manos a la obra.
Configuración
Primero, necesitamos un contenedor con otro elemento interno. El contenedor ayudará con la perspectiva.
<div id="container">
<div id="inner"></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 la #container
a 40px
que no hace nada en este punto porque no hemos creado ninguna transformación. Eso se manejará más adelante en JavaScript.
Vea el contenedor de imágenes 3D de la pluma – Parte 0 de Mihai (@MihaiIonescu) en CodePen.
Empecemos a programar
Aquí está el esquema 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 (o harán) haciendo:
- Funciones del 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 lo hemos codificado, pero su objetivo será actualizar la rotación 3D de nuestro
#inner
div. - Hora de actualizar la función: Esta es otra función que aún no hemos codificado, pero volverá
true
cuando se requiere una actualización. Ésta es una forma de reducir el número de llamadas alupdate()
funcionar 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 cuando el mouse se mueva sobre el contenedor.
- Restablece el estilo del div interno cuando el mouse sale 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 el counter
Alcanza el updateRate
, se realizará una actualización.
En este punto, puede intentar reemplazar el update
función por un console.log()
y jugar con el updateRate
para ver cómo funciona todo junto.
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 es nuevo en JavaScript.
// Init
var 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);
De nuevo, repasemos 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, relativo a(0,0)
.
La última línea de código mouse.setOrigin(container)
captura las coordenadas (0,0)
de nuestro mouse
Objeto al centro de nuestro contenedor. He aquí un ejemplo que lo ilustra.
Vea el contenedor de imágenes 3D de la pluma – Parte 1 de Mihai (@MihaiIonescu) en CodePen.
La idea detrás de todo esto es agregar más rotación a nuestra #inner
div a medida que mueve 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 suave como podría ser:
Vea el contenedor de imágenes 3D de la pluma – Parte 2 de Mihai (@MihaiIonescu) en CodePen.
¡Correcto! Le dijimos que actualizara la rotación de nuestro #inner
div cada vez que el counter
golpea el 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. Puede jugar con la perspectiva y transformar valores para hacer que el efecto sea más o menos dramático como mejor le parezca.
Vea el contenedor de imágenes 3D de la pluma – Parte 3 de Mihai (@MihaiIonescu) en CodePen.
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 tu container
después de cambiar el tamaño de la página.
Terminando
¡Terminamos! 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 esto se puede usar para otras cosas además de imágenes, incluidos formularios, modales o casi cualquier otro contenido que coloque en el contenedor. ¡Ve a experimentar!