Existem vários plugins para jQuery, React e até mesmo Angular para criar um carrossel de imagens, mas é possível criar utilizando apenas CSS puro.
Elementos de um carrossel
- Stage: A área disponível para o carrossel
- Item: O item visível atualmente pelo usuário
- Next/Prev Buttons: Os botões para passar aos items anteriores/próximos, que normalmente estão ocultos
Updates:
- 2021-01-25
- movido código para CodeSandbox
- revisão do texto do post
- grande redução no código fonte
Conceito
Vamos utilizar inputs do tipo radio
, que estarão ocultos para os usuários, em conjunto com a tag label
com o atributo for=""
, que ao ser clicada, automaticamente checa um radio que tenha o id correspondente.
Todos os input radio terão o mesmo atributo name
, assim o próprio navegador se encarrega de desmarcar e marcar os radios sem a necessidade de JavaScript.
Estrutura HTML do carrossel de images
Utilizaremos 4 inputs do tipo rádio pra controlar 4 imagens no carrossel. Repare que o primeiro item não tem o botão “anterior” e o último não tem o botão “próximo”.
<section class="carousel">
<input type="radio" name="carousel" id="carousel1" checked="checked" />
<input type="radio" name="carousel" id="carousel2" />
<input type="radio" name="carousel" id="carousel3" />
<input type="radio" name="carousel" id="carousel4" />
<main class="carousel__stage">
<aside class="carousel__item">
<img class="carousel__image" src="images/forest-1.jpg" />
<label for="carousel2" class="carousel__next carousel__control"></label>
</aside>
<aside class="carousel__item">
<label for="carousel1" class="carousel__prev carousel__control"></label>
<img class="carousel__image" src="images/sun-clouds.jpg" />
<label for="carousel3" class="carousel__next carousel__control"></label>
</aside>
<aside class="carousel__item">
<label for="carousel2" class="carousel__prev carousel__control"></label>
<img class="carousel__image" src="images/tree.jpg" />
<label for="carousel4" class="carousel__next carousel__control"></label>
</aside>
<aside class="carousel__item">
<label for="carousel3" class="carousel__prev carousel__control"></label>
<img class="carousel__image" src="images/flower.jpg" />
</aside>
</main>
</section>
A primeira coisa que precisamos fazer é ocultar os inputs para o usuário.
Será utilizada a técnica de mover o elemento para fora do viewport, pois alguns navegadores tratam inputs “ocultos” como estando desabilitados.
Desta maneira o input fica invisível, mas ainda é um elemento válido para os navegadores.
.carousel input {
position: absolute;
left: -10000px;
}
Vamos deixar o carrossel responsivo:
.carousel {
width: 80%;
height: 80%;
margin: 0 auto;
}
.carousel__stage {
overflow: hidden;
font-size: 0;
white-space: nowrap;
width: 100%;
height: 100%;
transition: text-indent 500ms;
position: relative;
}
.carousel__item {
display: inline-block;
text-indent: 0;
width: 100%;
height: 100%;
}
.carousel__image {
width: 100%;
height: 100%;
object-fit: cover;
}
Posicionamento dos botões Próximo / Anterior. Repare que o elemento stage é quem tem posicionamento relative, então todos os botões serão alinhados a ele.
Como os botões terão sua visibilidade oculta por padrão, ao movimentarmos de um item para o outro, vamos exibir os botões corretamente, dando uma ilusão para o usuário que o botão não mudou.
.carousel__control {
display: none;
position: absolute;
top: 50%;
color: #fff;
background: rgba(255, 255, 255, 0.3);
z-index: 1;
font-size: 1rem;
padding: 20px;
cursor: pointer;
}
.carousel__prev {
left: 0;
}
.carousel__prev::after {
content: ' << ';
display: inline-block;
}
.carousel__next {
right: 0;
}
.carousel__next::after {
content: ' >> ';
display: inline-block;
}
Agora é aonde a mágica começa.
Será utilizado o seletor :checked do css para sabermos qual é o input radio que está selecionado no momento.
Utilizando a propriedade text-indent
do CSS é possível movimentarmos o stage e dar a impressão de animação.
Nesta etapa temos que fazer um seletor para cada “estado” da animação:
#carousel1:checked ~ .carousel__stage {
text-indent: 0;
}
#carousel2:checked ~ .carousel__stage {
text-indent: -100%;
}
#carousel3:checked ~ .carousel__stage {
text-indent: -200%;
}
#carousel4:checked ~ .carousel__stage {
text-indent: -300%;
}
Para finalizar, vamos fazer a mágica de só mostrar os botões Próximo / Anterior
referentes ao item atual no stage:
#carousel1:checked ~ .carousel__stage .carousel__item:nth-child(1) .carousel__control,
#carousel2:checked ~ .carousel__stage .carousel__item:nth-child(2) .carousel__control,
#carousel3:checked ~ .carousel__stage .carousel__item:nth-child(3) .carousel__control,
#carousel4:checked ~ .carousel__stage .carousel__item:nth-child(4) .carousel__control {
display: block;
}
Resultado final
Você pode conferir o código fonte do exemplo aqui:
https://codesandbox.io/s/carousel-with-css-only-nshhx