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:
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.
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})
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!