Dark mode
Light mode
05 Abr 19
5 min

Criando uma galeria de imagens infinita com JavaScript puro

Neste artigo ensino a criar uma galeria de slides bem legal usando poucas linhas de código.

Fazer uma galeria de imagens é algo recorrente pra quem trabalha com front-end, essa semana eu tive a oportunidade de criar uma bem maneira e gostaria de compartilhar com vocês.

Ao final deste artigo, você vai ter algo assim:

Antes de começarmos, vamos entender o que será feito.

A ideia é termos um efeito de continuidade sempre que clicarmos para voltar ou avançar, para isso, precisamos de pelo menos mais um slide escondido do lado esquerdo e mais um do lado direito.

Se houverem mais slides, eles deverão se acumular do lado direito, simplesmente porque é mais fácil trabalhar com o CSS dessa maneira.

Ao clicar para mostrar o slide anterior, o último slide escondido do lado direito deve se tornar o primeiro slide da lista.

Ao clicar para mostrar o próximo slide, o primeiro slide (escondido) deverá ir para a última posição da lista.

Pra você visualizar melhor, criei esse esquema:

Esquema em SVG

Muito bem, agora que está tudo explicado, vamos primeiro criar a estrutura HTML e estilizar esses slides, então adicionar as funcionalidades.

Nossa estrutura

A estrutura do HTML é bem simples, vou utilizar classes para adicionar as imagens como plano de fundo e manter os slides proporcionais.

1<div class="gallery"> 2 <div class="gallery__prev"></div> 3 <div class="gallery__next"></div> 4 <div class="gallery__stream"> 5 <div class="gallery__item bg-1"></div> 6 <div class="gallery__item bg-2"></div> 7 <div class="gallery__item bg-3"></div> 8 <div class="gallery__item bg-4"></div> 9 <div class="gallery__item bg-5"></div> 10 <div class="gallery__item bg-6"></div> 11 <div class="gallery__item bg-7"></div> 12 </div> 13</div>

Estilizando!

Primeiro vamos estilizar a galeria e seus itens. Note que os elementos estão centralizados verticalmente, fiz isso somente para servir de exemplo.

1/* Global */ 2 3* { 4 margin: 0; 5 padding: 0; 6 box-sizing: border-box; 7} 8 9body { 10 background-color: #000; 11} 12 13/* Galeria */ 14 15.gallery { 16 position: absolute; 17 top: 50%; 18 transform: translateY(-50%); 19 width: 100%; 20 height: 90%; 21 max-height: 28vw; 22 overflow: hidden; 23} 24 25.gallery__stream { 26 position: relative; 27 top: 50%; 28 transform: translateY(-50%); 29 width: 100%; 30 height: 100%; 31} 32 33.gallery__item { 34 position: absolute; 35 width: 50%; 36 height: 100%; 37 transition: 1s all ease; 38 background-size: cover; 39 background-repeat: no-repeat; 40 background-position: center center; 41 border-radius: 5px; 42}

Perceba que foi adicionada uma propriedade transition no nosso item da galeria, é esse cara que vai dar esse efeito legal de escala quando trocamos de slide 😄

Agora posicionamos cada item da galeria, considerando também sua posição no eixo Z, e assim a gente evita que slides fiquem sobrepostos de maneira errada.

Para isso vamos usar o :nth-child, o seletor de filhos do CSS em que iremos estilizar os elementos de acordo com a ordem em que eles se apresentam dentro de um elemento pai em comum, mais informações sobre isso você encontra aqui.

1/* Itens */ 2 3.gallery__item:nth-child(1) { 4 left: 0; 5 z-index: 1; 6 transform: translateX(-100%) scale(0.8); 7} 8 9.gallery__item:nth-child(2) { 10 left: 0; 11 z-index: 2; 12 transform: translateX(-50%) scale(0.8); 13} 14 15.gallery__item:nth-child(3) { 16 left: 50%; 17 z-index: 4; 18 transform: translateX(-50%) scale(1); 19} 20 21.gallery__item:nth-child(4) { 22 left: 100%; 23 z-index: 2; 24 transform: translateX(-50%) scale(0.8); 25} 26 27.gallery__item:nth-child(n + 5) { 28 left: 100%; 29 z-index: 1; 30 transform: scale(0.8); 31}

Até aqui nada está sendo exibido, já que ainda não temos nossas imagens, então vamos criar as classes com os backgrounds:

1/* Backgrounds */ 2 3.bg-1 { 4 background-image: url(https://res.cloudinary.com/dm7h7e8xj/image/upload/v1554487589/star-wars-1_kgt8dr.jpg); 5} 6 7.bg-2 { 8 background-image: url(https://res.cloudinary.com/dm7h7e8xj/image/upload/v1554487590/star-wars-2_tgzyxe.jpg); 9} 10 11.bg-3 { 12 background-image: url(https://res.cloudinary.com/dm7h7e8xj/image/upload/v1554487591/star-wars-3_bkcmeb.jpg); 13} 14 15.bg-4 { 16 background-image: url(https://res.cloudinary.com/dm7h7e8xj/image/upload/v1554487591/star-wars-4_opgyza.jpg); 17} 18 19.bg-5 { 20 background-image: url(https://res.cloudinary.com/dm7h7e8xj/image/upload/v1554487591/star-wars-5_ulc9tx.jpg); 21} 22 23.bg-6 { 24 background-image: url(https://res.cloudinary.com/dm7h7e8xj/image/upload/v1554487591/star-wars-6_la8whc.jpg); 25} 26 27.bg-7 { 28 background-image: url(https://res.cloudinary.com/dm7h7e8xj/image/upload/v1554487590/star-wars-7_l3fcor.jpg); 29}

Pronto, o Anakin já pintou na tela!

Para fazer nossos botões de próximo e anterior, iremos estilizá-los exatamente como os slides visíveis na tela do lado esquerdo e do lado direito.

Iremos também posicioná-los uma camada acima desses slides, mas com um fundo transparente, assim irá parecer que estamos clicando nos slides, quando na verdade estamos clicando nos botões 😆

1/* Controles */ 2 3.gallery__prev, 4.gallery__next { 5 position: absolute; 6 top: 50%; 7 z-index: 4; 8 width: 50%; 9 height: 100%; 10 transform: translateX(-50%) translateY(-50%) scale(0.8); 11 cursor: pointer; 12} 13 14.gallery__prev { 15 left: 0; 16} 17 18.gallery__next { 19 left: 100%; 20}

Finalmente, por uma simples questão de estética, vamos adicionar um efeito de degradê nas laterais da galeria, utilizando os pseudo elementos :before e :after, mais sobre eles aqui.

Nota
Atenção ao z-index aqui! Se esses caras estiverem numa camada acima dos botões, não será possível clicar neles. Por isso, posicionamos esses elementos entre os slides e os botões transparentes.
1/* Sombras */ 2 3.gallery:before, 4.gallery:after { 5 display: block; 6 content: ""; 7 position: absolute; 8 top: 0; 9 width: 20%; 10 height: 100%; 11 z-index: 3; 12} 13 14.gallery:before { 15 left: 0; 16 background: linear-gradient( 17 to right, 18 rgba(0, 0, 0, 1) 0%, 19 rgba(0, 0, 0, 0) 100% 20 ); 21} 22 23.gallery:after { 24 right: 0; 25 background: linear-gradient( 26 to left, 27 rgba(0, 0, 0, 1) 0%, 28 rgba(0, 0, 0, 0) 100% 29 ); 30}

Fazendo funcionar

Agora que a parte mais trabalhosa já foi, vamos fazer funcionar. Primeiro temos de garantir que todos os elementos estão na tela, criando nossas funções após o evento DOMContentLoaded.

1document.addEventListener("DOMContentLoaded", function () { 2 // O código vem aqui 3})

Então selecionamos os elementos que precisamos:

1document.addEventListener("DOMContentLoaded", function () { 2 var stream = document.querySelector(".gallery__stream") 3 var items = document.querySelectorAll(".gallery__item") 4 var prev = document.querySelector(".gallery__prev") 5 var next = document.querySelector(".gallery__next") 6})

E por fim, adicionamos os eventos de clique nos botões prev e next:

1document.addEventListener("DOMContentLoaded", function () { 2 var stream = document.querySelector(".gallery__stream") 3 var items = document.querySelectorAll(".gallery__item") 4 var prev = document.querySelector(".gallery__prev") 5 var next = document.querySelector(".gallery__next") 6 7 prev.addEventListener("click", function () { 8 stream.insertBefore(items[items.length - 1], items[0]) 9 items = document.querySelectorAll(".gallery__item") 10 }) 11 12 next.addEventListener("click", function () { 13 stream.appendChild(items[0]) 14 items = document.querySelectorAll(".gallery__item") 15 }) 16})
Atenção
Perceba que atualizamos o valor da variável items, isso é muito importante, pois uma vez que modificamos a posição dos itens no DOM, a variável precisa ter esses itens atualizados na ordem correta ou estaremos selecionando os itens errados no próximo clique.

A ideia deste post foi mostrar como é fácil criar uma galeria bem bacana com poucas linhas de código, obviamente este código possui algumas limitações, como precisar ter no mínimo 5 slides para funcionar corretamente.

Além disso, há uma série de melhorias que poderiam ser implementadas aqui, deixo como sugestão algumas delas para você tentar:

  • Utilizar a lazysizes, ou qualquer outra lib de lazy loading para carregar as imagens somente quando elas forem ser exibidas.
  • Controlar a velocidade do clique do usuário, evitando que ele clique repetidas vezes nos botões, perdendo todo o efeito de transição.
  • Adicionar indicadores para o usuário saber em que slide está.

Espero que tenha curtido e até a próxima!

Compartilhe

Foto de Thiago sorrindo

Autor

Thiago Rossener

Desenvolvedor front-end, filósofo e espiritualista

Sua assinatura não pôde ser validada.
Você fez sua assinatura com sucesso.

Newsletter

Assinando minha newsletter você fica sabendo sempre que eu publicar algo novo, prometo que vai ser só isso.