CSS Control deslizante de imagen giratorio infinito y redondo | trucos CSS

Los controles deslizantes de imágenes (también llamados carruseles) están en todas partes. Hay muchos trucos de CSS para crear un control deslizante genérico donde las imágenes se deslizan de izquierda a derecha (o viceversa). Es lo mismo con las muchas bibliotecas de JavaScript que crean elegantes controles deslizantes con animaciones complejas No haremos nada de eso en esta publicación.

A través de una pequeña serie de artículos, exploraremos algunos controles deslizantes exclusivos de CSS fantásticos e inusuales. Si está cansado de mirar los mismos controles deslizantes clásicos, ¡entonces está en el lugar correcto!

Para este primer artículo, comenzaremos con algo que llamo un «deslizador de imagen giratorio circular»:

Genial, ¿verdad? ¡Analicemos el código!

marcado HTML

Si ha estado siguiendo mi serie sobre decoraciones de imágenes sofisticadas o cuadrículas CSS y formularios personalizados, entonces sabe que mi primera regla es trabajar con la menor cantidad de HTML posible. Siempre trato de encontrar soluciones CSS antes de desordenar mi código con demasiado <div>s y otras cosas.

La misma regla se aplica aquí: nuestro código no es más que una lista de imágenes en un contenedor.

Digamos que estamos trabajando con cuatro imágenes:

<div class="gallery">
  <img src="" alt="">
  <img src="" alt="">
  <img src="" alt="">
  <img src="" alt="">
</div>

¡Está! Ahora pasemos a la parte interesante del código. Pero primero nos sumergiremos en eso para comprender la lógica de cómo funciona nuestro control deslizante.

¿Cómo funciona?

Aquí hay un video donde elimino overflow: hidden Desde CSS para que podamos entender mejor cómo se mueven las imágenes:

Es como si nuestras cuatro imágenes estuvieran colocadas en un gran círculo que gira en sentido contrario a las agujas del reloj.

Todas las imágenes son del mismo tamaño (marcadas con S en la figura). Tenga en cuenta el círculo azul, que es el círculo que interseca el centro de todas las imágenes y tiene un radio (RNecesitaremos este valor más adelante para nuestra animación. R es igual a 0.707 * S(Omitiré la geometría que nos da esta ecuación).

¡Escribamos algo de CSS!

Usaremos CSS Grid para colocar todas las imágenes en la misma área una encima de la otra:

.gallery  {
  --s: 280px; /* control the size */

  display: grid;
  width: var(--s);
  aspect-ratio: 1;
  padding: calc(var(--s) / 20); /* we will see the utility of this later */
  border-radius: 50%;
}
.gallery > img {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

Nada complicado hasta ahora. La parte difícil es la animación.

Hablamos de rotar un gran círculo, pero en realidad rotaremos cada imagen individualmente, creando la ilusión de un gran círculo giratorio. Así que vamos a definir una animación, my aplicarlo a los elementos de la imagen:

.gallery > img {
  /* same as before */
  animation: m 8s infinite linear;
  transform-origin: 50% 120.7%;
}

@keyframes m {
  100% { transform: rotate(-360deg); }
}

El truco principal se basa en esta línea resaltada. Por defecto CSS transform-origin propiedad es igual a center (o 50% 50%), lo que hace que la imagen gire alrededor de su centro, pero no es necesario que lo haga. Necesitamos que la imagen gire alrededor del centro de un circulo grande que contiene nuestras imágenes, de ahí el nuevo valor de transform-origin.

Como R es igual a 0.707 * Spodemos decirlo R es igual a 70.7% del tamaño de la imagen. Aquí hay una figura que ilustra cómo llegamos 120.7% valor:

Ejecutemos la animación y veamos qué sucede:

Sé que sé. El resultado dista mucho de lo que queremos, pero en realidad estamos muy cerca. Puede parecer que solo hay una imagen allí, pero recuerda que hemos apilado todas las imágenes una encima de la otra. Todas giran al mismo tiempo y solo la imagen superior es visible. Lo que necesitamos es ralentizar la animación de cada imagen para evitar esta superposición.

.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */

¡Las cosas están mejorando!

Si ocultamos el desbordamiento del contenedor, ahora podemos ver un control deslizante, pero actualizaremos un poco la animación para que cada imagen permanezca visible durante un breve período de tiempo antes de continuar.

Actualizaremos nuestros fotogramas clave de animación para hacer precisamente eso:

@keyframes m {
  0%, 3% { transform: rotate(0); }
  22%, 27% { transform: rotate(-90deg); }
  47%, 52% { transform: rotate(-180deg); }
  72%, 77% { transform: rotate(-270deg); }
  98%, 100% { transform: rotate(-360deg); }
}

Para cada 90deg (360deg/4dónde 4 es el número de imágenes) añadiremos una pequeña pausa. Cada imagen permanecerá visible para 5% de la duración total antes de pasar a la siguiente (27%-22%, 52%-47%etc.). Voy a actualizar animation-timing-function usando un cubic-bezier() función para hacer la animación un poco más bonita:

¡Ahora nuestro control deslizante es perfecto! Bueno, casi perfecto porque aún nos falta el toque final: el colorido marco circular que rodea nuestras imágenes. Podemos usar el pseudo elemento de .gallery shell para hacerlo:

.gallery {
  padding: calc(var(--s) / 20); /* the padding is needed here */
  position: relative;
}
.gallery::after {
  content: "";
  position: absolute;
  inset: 0;
  padding: inherit; /* Inherits the same padding */
  border-radius: 50%;
  background: repeating-conic-gradient(#789048 0 30deg, #DFBA69 0 60deg);
  mask: 
    linear-gradient(#fff 0 0) content-box, 
    linear-gradient(#fff 0 0);
  mask-composite: exclude;
}
.gallery::after,
.gallery >img {
  animation: m 8s infinite cubic-bezier(.5, -0.2, .5, 1.2);
}

Creé un círculo con un degradado cónico repetido para el fondo mientras usaba un truco de enmascaramiento que solo muestra el área acolchada. Luego le aplico la misma animación que definimos para las imágenes.

¡Estamos listos! Tenemos un control deslizante circular genial:

Agreguemos más imágenes

Trabajar con cuatro imágenes está bien, pero sería mejor si pudiéramos escalarlo a cualquier número de imágenes. Después de todo, ese es el propósito del control deslizante de imágenes. Deberíamos poder echar un vistazo N imágenes

Para ello haremos el código más genérico introduciendo Sass Primero definimos una variable para el número de imágenes ($n) y actualizaremos cada parte en la que hayamos codificado el número de imágenes (4).

Comencemos con los retrasos:

.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */

La fórmula del retraso es (1 - $i)*duration/$nlo que nos da lo siguiente Bucle descarado:

@for $i from 2 to ($n + 1) {
  .gallery > img:nth-child(#{$i}) {
    animation-delay: calc(#{(1 - $i) / $n} * 8s);
  }
}

También podemos hacer que la duración sea variable si realmente queremos. Pero pasemos a la animación:

@keyframes m {
  0%, 3% { transform: rotate(0); }
  22%, 27% { transform: rotate(-90deg); }
  47%, 52% { transform: rotate(-180deg); }
  72%, 77% { transform: rotate(-270deg); }
  98%, 100% {transform: rotate(-360deg); }
}

Vamos a simplificarlo para obtener una mejor vista del modelo:

@keyframes m {
  0% { transform: rotate(0); }
  25% { transform: rotate(-90deg); }
  50% { transform: rotate(-180deg); }
  75% { transform: rotate(-270deg); }
  100% { transform: rotate(-360deg); }
}

El paso entre cada estado es igual a 25% – cual es 100%/4 – y añadimos un -90deg ángulo, que es -360deg/4Esto significa que, en cambio, podemos escribir nuestro ciclo de esta manera:

@keyframes m {
  0% { transform: rotate(0); }
  @for $i from 1 to $n {
    #{($i / $n) * 100}% { transform: rotate(#{($i / $n) * -360}deg); }  
  }
  100% { transform: rotate(-360deg); }
}

Porque cada imagen toma 5% de la animación, cambiamos esto:

#{($i / $n) * 100}%

…con este:

#{($i / $n) * 100 - 2}%, #{($i / $n) * 100 + 3}%

se debe notar que 5% es un valor aleatorio que elijo para este ejemplo. También podemos hacerlo variable para controlar cuánto tiempo debe permanecer visible cada imagen. Dejaré esto fuera por simplicidad, pero como tarea, ¡puedes intentar hacerlo y compartir tu desempeño en los comentarios!

@keyframes m {
  0%,3% { transform: rotate(0); }
  @for $i from 1 to $n {
    #{($i / $n) * 100 - 2}%, #{($i / $n) * 100 + 3}% { transform: rotate(#{($i / $n) * -360}deg); }  
  }
  98%,100% { transform: rotate(-360deg); }
}

Lo último es actualizar. transform-originVamos a necesitar algunos trucos geométricos. Sea cual sea el número de imágenes, la configuración es siempre la misma. Tenemos nuestras imágenes (círculos pequeños) colocadas dentro de un círculo grande y necesitamos encontrar el valor del radio, R.

Probablemente no quieras una explicación aburrida de la geometría, así es como la encontramos R:

R = S / (2 * sin(180deg / N))

Expresando esto como un porcentaje nos da:

R = 100% / (2 * sin(180deg / N)) = 50% / sin(180deg / N)

…lo que significa transform-origin valor es igual a:

transform-origin: 50% (50% / math.sin(180deg / $n) + 50%);

¡Estamos listos! ¡Tenemos un control deslizante que funciona con números aleatorios!

Pongamos nueve imágenes allí:

Añade tantas imágenes como quieras y actualiza $n variable con el número total de imágenes.

resumiendo

Con algunos trucos, utilizando transformaciones CSS y geometría estándar, hemos creado un buen control deslizante circular que no requiere mucho código. Lo mejor de este control deslizante es que no tenemos que molestarnos en duplicar las imágenes para mantener la animación infinita ya que tenemos un círculo. ¡Después de una rotación completa volveremos a la primera imagen!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

rtp live