Ante la pregunta de si es posible rotar libremente un elemento en la pantalla mediante el movimiento del ratón o el dedo (en las pantallas táctiles) sólo con HTML5 y CSS, la respuesta típica sería “no, no sin JavaScript” ... pero esta solución que proponemos sólo necesita unas pocas líneas de JS, y esta variación tiene la adición interesante de las variables CSS.
Objetos en el espacio
Comenzamos con una única imagen, para simplificar el ejemplo, en el espacio:
<img src="imagen.jpg" srcset="imagen-2x.jpg 2x" alt>
(Por supuesto, la página podría tener tantos elementos como deseas; hemos eliminado todo lo demás en aras de la simplicidad y la claridad).
El body se establece con margen 0 y un min-height de 100 vh, y utiliza Flexbox para centrar el elemento en la página:
body {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
perspective: 60vw;
margin: 0;
--mouseX: 0deg;
--mouseY: 0deg;
}
Además, configuramos un CSS 3D perspective, junto con dos variables CSS. Estas variables se utilizan para el estilo de la imagen:
img {
width: 80vmin;
height: 80vmin;
transform: rotateX(calc(var(--mouseY)))
rotateY(calc(var(--mouseX)));
}
Ten en cuenta que debido a que estamos usando más de una variable en la propiedad transform, hay que rodear cada una con calc() para evitar un error de sintaxis. En un futuro próximo, cuando rotateX e Y se conviertan en sus propias propiedades CSS, esto no será necesario.
La imagen necesita tanto una anchura como una altura, ya que de lo contrario Flexbox estirará la imagen.
Position Tracking
El código JavaScript se inicia mediante la identificación de la imagen:
const img = document.getElementsByTagName(“img")[0];
Si bien es normal que las variables CSS se definan y utilicen exclusivamente en el interior de una hoja de estilo, también es posible configurarlos desde JavaScript, usando setProperty. Lo que hemos hecho es ir al interior de una función que toma la posición actual del puntero, determina la altura y la anchura de la ventana del navegador (y lo divide por la mitad), y a continuación utiliza esta información para determinar la cantidad correcta de la rotación de la imagen:
function sway(xPos, yPos) {
let wh = window.innerHeight / 2;
ww = window.innerWidth / 2;
document.body.style.setProperty("--mouseX", (xPos - ww) / 25+"deg");
document.body.style.setProperty("--mouseY", (yPos - wh) / 25+"deg");
}
Esta función se inicia por tanto con el movimiento del ratón o el tacto:
document.addEventListener("mousemove", function(e) {
sway(e.clientX,e.clientY);
})
document.addEventListener("touchmove", function(e) {
e.preventDefault();
var touch = e.targetTouches[0];
if (touch) {
sway(touch.pageX, touch.pageY);
}
});
Ten en cuenta que los valores utilizados en las variables se intercambian: el movimiento en X crea la rotación de la imagen en Y, y el movimiento en Y crea la rotación en X.
El poder de las Variables
Como Lea Verou señaló en su reciente CSS Conf presentation, el apoyo casi universal de los navegadores para las variables CSS permite a los estilos mover de nuevo a la posición que tienen previsto mantener - la de presentación - mientras que JavaScript puede tener su papel tradicional de comportamiento. Las variables CSS permiten una comunicación fluida entre los dos.
Si necesitas apoyo en MS Edge e IE, (y superar las limitaciones actuales de Firefox) podrías escribir la función exclusivamente en JavaScript:
function sway(xPos, yPos) {
img.style.transform = "rotateX("+(yPos - wh) / 25+"deg) rotateY("+(xPos - ww) / 25 +"deg)";
}
Comentarios