CSS Infinite 3D Sliders PlatoBlockchain Data Intelligence. Pesquisa vertical. Ai.

Controles deslizantes 3D infinitos CSS

Nesta série, temos feito sliders de imagem com nada além de HTML e CSS. A ideia é que podemos usar a mesma marcação, mas CSS diferente para obter resultados muito diferentes, não importa quantas imagens colocamos. Começamos com um controle deslizante circular que gira infinitamente, como um girador de fidget que contém imagens. Então fizemos um que folheia uma pilha de fotos.

Desta vez, estamos mergulhando na terceira dimensão. Vai parecer difícil no começo, mas muito do código que estamos vendo é exatamente o que usamos nos dois primeiros artigos desta série, com algumas modificações. Portanto, se você está entrando na série agora, sugiro verificar os outros para contextualizar os conceitos que estamos usando aqui.

Série de controles deslizantes CSS

É isso que pretendemos:

À primeira vista, parece que temos um cubo giratório com quatro imagens. Mas, na realidade, estamos lidando com seis imagens no total. Aqui está o controle deslizante de um ângulo diferente:

Agora que temos um bom visual de como as imagens são organizadas, vamos dissecar o código para ver como chegamos lá.

A configuração básica

Mesmo HTML do resto dos controles deslizantes que usamos para os outros controles deslizantes:

E mais uma vez, estamos usando o CSS Grid para colocar as imagens em uma pilha, uma em cima da outra:

.gallery {
  display: grid;
}
.gallery > img {
  grid-area: 1 / 1;
  width: 160px;
  aspect-ratio: 1;
  object-fit: cover;
}

A animação

A lógica desse controle deslizante é muito semelhante à o controle deslizante circular do primeiro artigo. Na verdade, se você verificar o vídeo acima novamente, poderá ver que as imagens são colocadas de forma a criar um polígono. Após uma rotação completa, ele retorna à primeira imagem.

Contamos com o CSS transform-origin e animation-delay propriedades para esse primeiro controle deslizante. A mesma animação é aplicada a todos os elementos da imagem, que giram em torno do mesmo ponto. Então, usando diferentes atrasos, colocamos corretamente todas as imagens em torno de um grande círculo.

A implementação será um pouco diferente para nosso controle deslizante 3D. Usando transform-origin não vai funcionar aqui porque estamos trabalhando em 3D, então vamos usar transform em vez disso, coloque todas as imagens corretamente e gire o contêiner.

Estamos alcançando o Sass novamente para que possamos percorrer o número de imagens e aplicar nossas transformações:

@for $i from 1 to ($n + 1) {
  .gallery > img:nth-child(#{$i}) {
     transform: 
       rotate(#{360*($i - 1) / $n}deg) /* 1 */
       translateY(50% / math.tan(180deg / $n)) /* 2 */ 
       rotateX(90deg); /* 3 */
  }
}

Você pode estar se perguntando por que estamos pulando direto para o Sass. Começamos com um número fixo de imagens usando Vanilla CSS nos outros artigos antes de generalizar o código com Sass para contabilizar qualquer número (N) de imagens. Bem, acho que você entendeu a ideia agora e podemos cortar todo esse trabalho de descoberta para chegar à implementação real.

A transform propriedade está assumindo três valores, que ilustrei aqui:

Controles deslizantes 3D infinitos CSS

Primeiro giramos todas as imagens umas sobre as outras. O ângulo de rotação depende do número de imagens. Por N imagens, temos um incremento igual a 360deg/N. Então nós translate todas as imagens na mesma quantidade de forma que seus pontos centrais se encontrem nas laterais.

Mostrando a pilha de imagens dispostas planas em um círculo com uma linha vermelha passando pelo ponto central das imagens.
Controles deslizantes 3D infinitos CSS

Há alguma geometria chata que ajuda a explicar como tudo isso funciona, mas a distância é igual a 50%/tan(180deg/N). Lidamos com uma equação semelhante ao fazer o controle deslizante circular ( transform-origin: 50% 50%/sin(180deg/N) ).

Finalmente, rotacionamos as imagens em torno do eixo x por 90deg para obter o arranjo que queremos. Aqui está um vídeo que ilustra o que a última rotação está fazendo:

Agora tudo o que precisamos fazer é girar todo o contêiner para criar nosso controle deslizante infinito.

.gallery {
  transform-style: preserve-3d;
  --_t: perspective(280px) rotateX(-90deg);
  animation: r 12s cubic-bezier(.5, -0.2, .5, 1.2) infinite;
}
@keyframes r {
  0%, 3% {transform: var(--_t) rotate(0deg); }
  @for $i from 1 to $n {
    #{($i/$n)*100 - 2}%, 
    #{($i/$n)*100 + 3}% {
      transform: var(--_t) rotate(#{($i / $n) * -360}deg);
    }  
  }
  98%, 100% { transform: var(--_t) rotate(-360deg); }
}

Esse código pode ser difícil de entender, então vamos voltar um pouco e revisitar a animação que fizemos para o controle deslizante circular. Isto é o que escrevemos naquele primeiro artigo:

.gallery {
  animation: m 12s cubic-bezier(.5, -0.2, .5, 1.2) infinite;
}
@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); }
}

Os quadros-chave são quase idênticos. Temos os mesmos valores percentuais, o mesmo loop e a mesma rotação.

Por que ambos são iguais? Porque a lógica deles é a mesma. Em ambos os casos, as imagens são dispostas em torno de uma forma circular e precisamos girar tudo para mostrar cada imagem. Foi assim que consegui copiar os quadros-chave do controle deslizante circular e usar o mesmo código para nosso controle deslizante 3D. A única diferença é que precisamos girar o contêiner por -90deg ao longo do eixo x para ver as imagens, pois já as rotacionamos 90deg no mesmo eixo. Em seguida, adicionamos um toque de perspective para obter o efeito 3D.

É isso! Nosso controle deslizante está pronto. Aqui está a demonstração completa novamente. Tudo o que você precisa fazer é adicionar quantas imagens quiser e atualizar uma variável para começar.

Controle deslizante vertical 3D

Já que estamos jogando no espaço 3D, por que não fazer uma versão vertical do slider anterior? O último gira ao longo do eixo z, mas também podemos mover ao longo do eixo x, se quisermos.

Se você comparar o código para ambas as versões deste controle deslizante, talvez não identifique imediatamente a diferença porque é apenas um caractere! eu substituí rotate() de rotateX() dentro dos quadros-chave e da imagem transform. É isso aí!

Deve notar-se que rotate() é equivalente a rotateZ(), portanto, alterando o eixo de Z para X transformamos o controle deslizante da versão horizontal para a vertical.

Cubo deslizante

Não podemos falar de 3D em CSS sem falando sobre cubos. E sim, isso significa que vamos fazer outra versão do controle deslizante.

A ideia por trás desta versão do controle deslizante é criar uma forma de cubo real com as imagens e girar tudo em torno dos diferentes eixos. Como é um cubo, estamos lidando com seis faces. Usaremos seis imagens, uma para cada face do cubo. Então, sem Sass, mas de volta ao CSS vanilla.

Essa animação é um pouco esmagadora, certo? Por onde você começa?

Temos seis faces, então precisamos realizar pelo menos seis rotações para que cada imagem tenha uma volta. Bem, na verdade, precisamos de cinco rotações — a última nos traz de volta à face da primeira imagem. Se você pegar um cubo de Rubik — ou algum outro objeto em forma de cubo como um dado — e girá-lo com a mão, terá uma boa ideia do que estamos fazendo.

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

  transform-style: preserve-3d;
  --_p: perspective(calc(2.5*var(--s)));
  animation: r 9s infinite cubic-bezier(.5, -0.5, .5, 1.5);
}

@keyframes r {
  0%, 3%   { transform: var(--_p); }
  14%, 19% { transform: var(--_p) rotateX(90deg); }
  31%, 36% { transform: var(--_p) rotateX(90deg) rotateZ(90deg); }
  47%, 52% { transform: var(--_p) rotateX(90deg) rotateZ(90deg) rotateY(-90deg); }
  64%, 69% { transform: var(--_p) rotateX(90deg) rotateZ(90deg) rotateY(-90deg) rotateX(90deg); }
  81%, 86% { transform: var(--_p) rotateX(90deg) rotateZ(90deg) rotateY(-90deg) rotateX(90deg) rotateZ(90deg); }
  97%, 100%{ transform: var(--_p) rotateX(90deg) rotateZ(90deg) rotateY(-90deg) rotateX(90deg) rotateZ(90deg) rotateY(-90deg); }
}

A transform A propriedade começa com zero rotações e, em cada estado, adicionamos uma nova rotação em um eixo específico até atingirmos seis rotações. Então voltamos à primeira imagem.

Não vamos esquecer a colocação de nossas imagens. Cada um é aplicado a uma face do cubo usando transform:

.gallery img {
  grid-area: 1 / 1;
  width: var(--s);
  aspect-ratio: 1;
  object-fit: cover;
  transform: var(--_t,) translateZ(calc(var(--s) / 2));
}
.gallery img:nth-child(2) { --_t: rotateX(-90deg); }
.gallery img:nth-child(3) { --_t: rotateY( 90deg) rotate(-90deg); }
.gallery img:nth-child(4) { --_t: rotateX(180deg) rotate( 90deg); }
.gallery img:nth-child(5) { --_t: rotateX( 90deg) rotate( 90deg); }
.gallery img:nth-child(6) { --_t: rotateY(-90deg); }

Você provavelmente está pensando que há uma lógica estranha e complexa por trás dos valores que estou usando, certo? Bem não. Tudo o que fiz foi abrir o DevTools e brincar com diferentes valores de rotação para cada imagem até acertar. Pode parecer estúpido, mas, ei, funciona - especialmente porque temos um número fixo de imagens e não estamos procurando por algo que suporte N imagens.

Na verdade, esqueça os valores que estou usando e tente fazer a colocação sozinho como um exercício. Comece com todas as imagens empilhadas umas sobre as outras, abra o DevTools e pronto! Você provavelmente terminará com um código diferente e tudo bem. Pode haver diferentes maneiras de posicionar as imagens.

Qual é o truque com a vírgula dentro do var()? É um erro de digitação?

Não é um erro de digitação, então não o remova! Se você removê-lo, notará que afeta o posicionamento da primeira imagem. Você pode ver que no meu código eu defini --_t para todas as imagens, exceto a primeira, porque só preciso de uma tradução para ela. Essa vírgula faz com que a variável volte a um valor nulo. Sem a vírgula, não teremos fallback e todo o valor será inválido.

De a especificação:

Nota: Ou seja, var(--a,) é uma função válida, especificando que se o --a propriedade personalizada for inválida ou ausente, o var()` deve ser substituído por nada.

Controle deslizante de cubo aleatório

Um pouco de aleatoriedade pode ser um bom aprimoramento para esse tipo de animação. Portanto, em vez de girar o cubo em ordem sequencial, podemos rolar os dados, por assim dizer, e deixar o cubo rolar como quiser.

Legal certo? Não sei vocês, mas eu gosto mais dessa versão! É mais interessante e as transições são satisfatórias de assistir. E adivinha? Você pode brincar com os valores para criar seu próprio controle deslizante de cubo aleatório!

A lógica é real, não aleatória - apenas parece assim. Você define um transform em cada quadro-chave que permite mostrar um rosto e… bem, é isso mesmo! Você pode escolher qualquer pedido que desejar.

@keyframes r {
  0%, 3%   { transform: var(--_p) rotate3d( 0, 0, 0,  0deg); }
  14%,19%  { transform: var(--_p) rotate3d(-1, 1, 0,180deg); }
  31%,36%  { transform: var(--_p) rotate3d( 0,-1, 0, 90deg); }
  47%,52%  { transform: var(--_p) rotate3d( 1, 0, 0, 90deg); }
  64%,69%  { transform: var(--_p) rotate3d( 1, 0, 0,-90deg); }
  81%,86%  { transform: var(--_p) rotate3d( 0, 1, 0, 90deg); }
  97%,100% { transform: var(--_p) rotate3d( 0, 0, 0,  0deg); }
}

Eu estou usando rotate3d() desta vez, mas ainda estou contando com o DevTools para encontrar os valores que parecem "certos" para mim. Não tente encontrar uma relação entre os quadros-chave porque simplesmente não existe. Estou definindo transformações separadas e observando o resultado “aleatório”. Certifique-se de que a primeira imagem seja o primeiro e o último quadro, respectivamente, e mostre uma imagem diferente em cada um dos outros quadros.

Você não é obrigado a usar um rotate3d() transformar como eu fiz. Você também pode encadear diferentes rotações como fizemos no exemplo anterior. Brinque e veja o que você pode inventar! Estarei esperando por você para compartilhar sua versão comigo na seção de comentários!

Resumindo

Espero que tenham gostado desta pequena série. Construímos alguns controles deslizantes divertidos (e engraçados) enquanto aprendíamos muito sobre todos os tipos de conceitos de CSS ao longo do caminho — desde posicionamento de grade e ordem de empilhamento até atrasos e transformações de animação. Até brincamos com uma pitada de Sass para percorrer uma série de elementos.

E fizemos tudo exatamente com o mesmo HTML para cada controle deslizante que criamos. Quão legal é isso? CSS é muito poderoso e capaz de realizar muito sem a ajuda de JavaScript.

Carimbo de hora:

Mais de Truques CSS