CSS Infinite Slider Desplazamiento de imágenes Polaroid | trucos CSS
En el último artículo, creamos un pequeño control deslizante (o "carrusel" si lo prefiere) bastante genial que gira en una dirección circular. Esta vez haremos uno que hojee una pila de imágenes Polaroid.
Genial, ¿verdad? No mires el código todavía porque hay mucho que descubrir. Únete a mí, ¿de acuerdo?
La configuración básica
La mayor parte del HTML y CSS de este control deslizante es similar al circular que hicimos la última vez. De hecho, usamos exactamente el mismo marcado:
<div class="gallery">
<img src="" alt="">
<img src="" alt="">
<img src="" alt="">
<img src="" alt="">
</div>
Y este es el CSS principal que establece nuestro padre .gallery
un contenedor en forma de cuadrícula donde todas las imágenes se apilan una encima de la otra:
.gallery {
display: grid;
width: 220px; /* controls the size */
}
.gallery > img {
grid-area: 1 / 1;
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border: 10px solid #f2f2f2;
box-shadow: 0 0 4px #0007;
}
Nada complicado hasta ahora. Incluso para el estilo Polaroid de las imágenes, todo lo que uso es pequeño. border
y box-shadow
.. Es posible que puedas hacerlo mejor, ¡así que siéntete libre de jugar con estos estilos decorativos! Pondremos la mayor parte de nuestro enfoque en la animación, que es la parte más complicada.
¿Cuál es el truco?
La lógica de este control deslizante se basa en el orden en que se apilan las imágenes, así que sí, vamos a jugar con z-index
.Todas las imágenes comienzan con el mismo z-index
valor (2
), lo que lógicamente colocaría la última imagen en la parte superior de la pila.
Tomamos la última imagen y la arrastramos hacia la derecha hasta que revele la siguiente imagen en la pila. Luego reducimos la imagen z-index
valor, luego lo deslizamos de nuevo en el mazo z-index
valor es más bajo que las otras imágenes, se convierte en la última imagen de la pila.
Aquí hay una demostración que muestra el truco. Pase el cursor sobre la imagen para activar la animación:
Ahora imagina el mismo truco aplicado a todas las imágenes. Aquí está el patrón si usamos :nth-child()
pseudo-selector para distinguir imágenes:
- Arrastre la última imagen (
N
La siguiente imagen es visible (N - 1
). - Arrastra la siguiente imagen (
N - 1
La siguiente imagen es visible (N - 2
) - Arrastra la siguiente imagen (
N - 2
La siguiente imagen es visible (N - 3
) - (Seguimos el mismo proceso hasta llegar a la primera imagen)
- Arrastra la primera imagen (
1
).La última imagen (N
) se vuelve a ver.
¡Este es nuestro deslizador infinito!
Disección de animación
Si recuerdas el artículo anterior, definí solo una animación y jugué con retrasos para controlar cada imagen. Aquí haremos lo mismo. Primero intentemos visualizar la línea de tiempo de nuestra animación. Comenzaremos con tres imágenes, luego sumaremos más tarde para obtener un número aleatorio (N
) a partir de imágenes.
Nuestra animación se divide en tres partes: "deslizar hacia la derecha", "deslizar hacia la izquierda" y "no mover". Podemos identificar fácilmente el retraso entre cada imagen. Si consideramos que la primera imagen comienza desde 0s
y la duración es igual a 6s
entonces el segundo comenzará desde -2s
y el tercero en -4s
.
.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 6s / 3 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 6s / 3 */
También podemos ver que la parte "no se mueve" ocupa dos tercios de toda la animación (2*100%/3
), mientras que las partes de deslizamiento hacia la derecha y hacia la izquierda ocupan un tercio juntas, por lo que cada una es igual a 100%/6
de toda la animación.
Podemos escribir nuestros fotogramas clave de animación de esta manera:
@keyframes slide {
0% { transform: translateX(0%); }
16.67% { transform: translateX(120%); }
33.34% { transform: translateX(0%); }
100% { transform: translateX(0%); }
}
que 120%
es un valor arbitrario. Necesitaba algo más grande que 100%
. Las imágenes deben deslizarse a la derecha de otras imágenes. Para hacer esto, necesita moverse al menos 100%
de su tamaño Así que fui 120%
— para ganar espacio adicional.
Ahora tenemos que mirar z-index
Recuerda que necesitamos actualizar la imagen. z-index
valor después se desliza hacia la derecha de la pila y antes de lo deslizamos hacia el fondo de la pila.
@keyframes slide {
0% { transform: translateX(0%); z-index: 2; }
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
33.34% { transform: translateX(0%); z-index: 1; }
100% { transform: translateX(0% ); z-index: 1; }
}
En lugar de definir un estado de 16.67%
(100%/6
) en la línea de tiempo, definimos dos estados en puntos casi idénticos (16.66%
y 16.67%
) dónde z-index
el valor disminuye antes de que deslicemos la imagen de regreso a la plataforma.
Esto es lo que sucede cuando lo ponemos todo junto:
Hmmm, la parte deslizante parece funcionar bien, ¡pero el orden de la pila está desordenado! La animación comienza bien cuando la imagen superior retrocede... pero las siguientes imágenes no siguen. Si nota, la segunda imagen en la Secuencia vuelve a la parte superior de la pila antes de que la siguiente imagen parpadee encima de ella.
tenemos que vigilar de cerca z-index
Inicialmente, todas las imágenes son z-index: 2
Esto significa que el orden de apilamiento debería ser...
Our eyes 👀 --> 3rd (2) | 2nd (2) | 1st (2)
Arrastramos la tercera imagen y la actualizamos z-index
para recibir este pedido:
Our eyes 👀 --> 2nd (2) | 1st (2) | 3rd (1)
Hacemos lo mismo con el segundo:
Our eyes 👀 --> 1st (2) | 3rd (1) | 2nd (1)
...y el primero:
Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)
Hacemos esto y todo parece estar bien. ¡Pero en realidad no lo es! Cuando la primera imagen se mueva hacia atrás, la tercera imagen comenzará otra iteración, lo que significa que volverá a z-index: 2
:
Our eyes 👀 --> 3rd (2) | 2nd (1) | 1st (1)
así que en en realidad nunca tuvimos todas las imágenes z-index: 2
¡en absoluto! Cuando las imágenes no se mueven (es decir, la parte "no se mueve" de la animación), z-index
es 1
Si arrastramos la tercera imagen y la actualizamos z-index
valor de 2
a 1
se mantendrá en la cima! Cuando todas las imágenes son iguales z-index
la última en el orden de origen, nuestra tercera imagen en este caso, está en la parte superior de la pila. Arrastrar la tercera imagen da como resultado lo siguiente:
Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)
La tercera imagen todavía está en la parte superior, y justo después de ella, movemos la segunda imagen en la parte superior cuando su animación se reinicia en z-index: 2
:
Our eyes 👀 --> 2nd (2) | 3rd (1) | 1st (1)
Después de arrastrarlo, obtenemos:
Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)
Entonces la primera imagen saltará encima:
Our eyes 👀 --> 1st(2) | 3rd (1) | 2nd (1)
Está bien, estoy perdido. Entonces, ¿la lógica está mal?
Lo sé, es confuso, pero nuestra lógica no está del todo equivocada. Solo tenemos que modificar un poco la animación para que todo funcione como queremos. El truco es resetear correctamente z-index
.
Tomemos la situación en la que la tercera imagen está en la parte superior:
Our eyes 👀 --> 3rd (2) | 2nd (1) | 1st (1)
Vimos este arrastre en la tercera imagen y su cambio. z-index
lo mantiene arriba. Lo que tenemos que hacer es actualizar z-index
en la segunda imagen. Entonces, antes de deslizar la tercera imagen del mazo, actualizamos z-index
de la segunda imagen a 2
.
En otras palabras, reiniciamos z-index
de la segunda imagen antes del final de la animación.
El símbolo más verde representa incremento z-index
a 2
y el símbolo rojo menos se correlaciona con z-index: 1
.La segunda imagen comienza con z-index: 2
luego lo actualizamos a 1
cuando se sale de la cubierta. Pero antes de que la primera imagen se deslice, cambiamos z-index
de la segunda imagen volver a 2
Esto asegurará que ambas imágenes sean iguales. z-index
pero aún así el tercero permanecerá en la parte superior porque aparece más tarde en el DOM. Pero después de que aparece la tercera imagen, también lo hace su z-index
se actualiza, se mueve a la parte inferior.
Eso es dos tercios del camino a través de la animación, así que actualicemos nuestros fotogramas clave en consecuencia:
@keyframes slide {
0% { transform: translateX(0%); z-index: 2; }
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
33.34% { transform: translateX(0%); z-index: 1; }
66.33% { transform: translateX(0%); z-index: 1; }
66.34% { transform: translateX(0%); z-index: 2; } /* and also here */
100% { transform: translateX(0%); z-index: 2; }
}
Un poco mejor, pero aún no. bastante hay otro problema...
¡Ay no, esto nunca terminará!
No se preocupe, no volveremos a cambiar los fotogramas clave porque este problema solo ocurre cuando se incluye la última imagen. Podemos hacer una animación de fotogramas clave "especial" específicamente para la última imagen para arreglar las cosas.
Cuando la primera imagen está en la parte superior, tenemos la siguiente situación:
Our eyes 👀 --> 1st (2) | 3rd (1) | 2nd (1)
Dado el ajuste anterior que hicimos, la tercera imagen saltará encima antes de que se deslice la primera. Esto solo sucede en esta situación porque la siguiente imagen que se mueve después de la primera imagen es ultimo imagen que tiene un orden superior en el DOM. El resto de las imágenes están bien porque tenemos N
después N - 1
entonces empezamos desde 3
a 2
y 2
a 1
… pero luego empezamos desde 1
a N
.
Para evitar esto, usaremos los siguientes fotogramas clave para la imagen final:
@keyframes slide-last {
0% { transform: translateX(0%); z-index: 2;}
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
33.34% { transform: translateX(0%); z-index: 1; }
83.33% { transform: translateX(0%); z-index: 1; }
83.34% { transform: translateX(0%); z-index: 2; } /* and also here */
100% { transform: translateX(0%); z-index: 2; }
}
Fueron puestos z-index
valor 5/6 a través de la animación (en lugar de dos tercios), que es cuando la primera imagen está fuera de la pila. ¡Así que no vemos picos!
¡DESPUÉS! ¡Nuestro deslizador infinito ahora es perfecto! Aquí está nuestro código final en todo su esplendor:
.gallery > img {
animation: slide 6s infinite;
}
.gallery > img:last-child {
animation-name: slide-last;
}
.gallery > img:nth-child(2) { animation-delay: -2s; }
.gallery > img:nth-child(3) { animation-delay: -4s; }
@keyframes slide {
0% { transform: translateX(0%); z-index: 2; }
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; }
33.34% { transform: translateX(0%); z-index: 1; }
66.33% { transform: translateX(0%); z-index: 1; }
66.34% { transform: translateX(0%); z-index: 2; }
100% { transform: translateX(0%); z-index: 2; }
}
@keyframes slide-last {
0% { transform: translateX(0%); z-index: 2; }
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; }
33.34% { transform: translateX(0%); z-index: 1; }
83.33% { transform: translateX(0%); z-index: 1; }
83.34% { transform: translateX(0%); z-index: 2; }
100% { transform: translateX(0%); z-index: 2; }
}
Soporta cualquier número de imágenes.
Ahora que tenemos nuestra animación funcionando para tres imágenes, hagamos que funcione para un número arbitrario (N
) a partir de imágenes. Pero primero podemos optimizar un poco nuestro trabajo dividiendo la animación para evitar la redundancia:
.gallery > img {
z-index: 2;
animation:
slide 6s infinite,
z-order 6s infinite steps(1);
}
.gallery > img:last-child {
animation-name: slide, z-order-last;
}
.gallery > img:nth-child(2) { animation-delay: -2s; }
.gallery > img:nth-child(3) { animation-delay: -4s; }
@keyframes slide {
16.67% { transform: translateX(120%); }
33.33% { transform: translateX(0%); }
}
@keyframes z-order {
16.67%,
33.33% { z-index: 1; }
66.33% { z-index: 2; }
}
@keyframes z-order-last {
16.67%,
33.33% { z-index: 1; }
83.33% { z-index: 2; }
}
¡Mucho menos código ahora! Hacemos una animación para la parte deslizante y otra para la z-index
actualizaciones Tenga en cuenta que usamos steps(1)
en z-index
animación. Es porque quiero hacer un cambio drástico. z-index
value en oposición a la animación deslizante donde queremos un movimiento suave.
Ahora que el código es más fácil de leer y mantener, tenemos una mejor visión de cómo encontrar una solución para admitir cualquier cantidad de imágenes. Lo que debemos hacer es actualizar los retrasos de animación y las tasas de fotogramas clave. Los retrasos son fáciles porque podemos usar exactamente el mismo ciclo que hicimos en el último artículo para admitir varias imágenes en el control deslizante circular:
@for $i from 2 to ($n + 1) {
.gallery > img:nth-child(#{$i}) {
animation-delay: calc(#{(1 - $i)/$n}*6s);
}
}
Esto significa que nos estamos moviendo de Vanilla CSS a Sass. Entonces tenemos que imaginar cómo se escala la línea de tiempo con N
No olvidemos que la animación se desarrolla en tres fases:
Después de 'deslizar hacia la derecha' y 'deslizar hacia la izquierda', la imagen debe permanecer colocada hasta que el resto de las imágenes pasen por la secuencia. Entonces, la parte "sin moverse" debería tomar el mismo tiempo que (N - 1
) como "deslizar hacia la derecha" y "deslizar hacia la izquierda". Y dentro de una iteración, N
las imágenes se deslizarán. Entonces, "deslizar a la derecha" y "deslizar izquierda' ambos 100%/N
de la línea de tiempo general de la animación. La imagen se desliza de la pila en (100%/N)/2
y se desliza hacia atrás en 100%/N
.
Podemos cambiar esto:
@keyframes slide {
16.67% { transform: translateX(120%); }
33.33% { transform: translateX(0%); }
}
...a esto:
@keyframes slide {
#{50/$n}% { transform: translateX(120%); }
#{100/$n}% { transform: translateX(0%); }
}
si reemplazamos N
con 3
Nosotros recibimos 16.67%
y 33.33%
cuando hay 3
imágenes en la pila. Es la misma lógica con el orden de clasificación, donde tendremos esto:
@keyframes z-order {
#{50/$n}%,
#{100/$n}% { z-index: 1; }
66.33% { z-index: 2; }
}
Todavía tenemos que actualizar 66.33%
Aquí debería ser donde la imagen se reinicia z-index
antes del final de la animación. Al mismo tiempo, la siguiente imagen comienza a deslizarse. Porque la parte deslizante toma 100%/N
el reinicio debe hacerse en 100% - 100%/N
:
@keyframes z-order {
#{50/$n}%,
#{100/$n}% { z-index: 1; }
#{100 - 100/$n}% { z-index: 2; }
}
pero por lo nuestro z-order-last
para que la animación funcione, debe ocurrir un poco más tarde en la secuencia. ¿Recuerdas el ajuste que hicimos a la última imagen? Restablecer el z-index
El valor debe ocurrir cuando la primera imagen salta de la pila, no cuando comienza a deslizarse. Podemos usar el mismo razonamiento aquí en nuestros fotogramas clave:
@keyframes z-order-last {
#{50/$n}%,
#{100/$n}% { z-index: 1; }
#{100 - 50/$n}% { z-index: 2; }
}
¡Estamos listos! Esto es lo que obtenemos cuando usamos cinco imágenes:
Podemos agregar un ligero giro para hacer las cosas un poco más bonitas:
Todo lo que he hecho es agregar rotate(var(--r))
a transform
Dentro del bucle, --r
se define por un ángulo arbitrario:
@for $i from 1 to ($n + 1) {
.gallery > img:nth-child(#{$i}) {
--r: #{(-20 + random(40))*1deg}; /* a random angle between -20deg and 20deg */
}
}
La rotación causa algunos problemas menores, ya que a veces podemos ver que algunas de las imágenes saltan al final de la pila, pero no es gran cosa.
resumiendo
Todo esto z-index
el trabajo fue un gran acto de equilibrio, ¿no? Si no estaba seguro de cómo funcionaba el orden de clasificación antes de este ejercicio, ¡probablemente ahora tenga una idea mucho mejor! Si encontró algunas de las explicaciones difíciles de seguir, le recomiendo que vuelva a leer el artículo y delinee las cosas con lápiz y papel. Intenta ilustrar cada paso de la animación usando un número diferente de imágenes para entender mejor el truco.
La última vez usamos algunos trucos geométricos para crear un control deslizante circular que gira de regreso a la primera imagen después de una secuencia completa. Esta vez logramos un truco similar usando z-index
En ambos casos, no duplicamos ninguna de las imágenes para simular una animación continua, ni recurrimos a JavaScript para ayudar con los cálculos.
La próxima vez haremos controles deslizantes 3D. ¡Manténganse al tanto!
Deja una respuesta