This page explains how to create an image carousel in pure JavaScript and CSS.
The carousel is composed of five visible images and an invisible image (use to load the next image).
I'm going over the creation in the main lines, but if you want me to detail a point, don't hesitate to contact me.
Here is the final result:
Let start by creating the images in the HTML.
The six images are encapsulted in a main div named carousel
.
Each image has a unique ID and belongs to the class carousel-image
<div id="carousel">
<img src="https://lucidar.me/fr/web-dev/files/img0.svg" id="carousel-image-0" class="carousel-image">
<img src="https://lucidar.me/fr/web-dev/files/img1.svg" id="carousel-image-1" class="carousel-image">
<img src="https://lucidar.me/fr/web-dev/files/img2.svg" id="carousel-image-2" class="carousel-image">
<img src="https://lucidar.me/fr/web-dev/files/img3.svg" id="carousel-image-3" class="carousel-image">
<img src="https://lucidar.me/fr/web-dev/files/img4.svg" id="carousel-image-4" class="carousel-image">
<img src="https://lucidar.me/fr/web-dev/files/img5.svg" id="carousel-image-5" class="carousel-image">
</div>
Let's now add some CSS to place the images at there original position. First, we center the carousel in the middle of the page. Of course, you can modify this to your needs.
#carousel {
width: 100%;
max-width: 100vw;
height: 21vh;
position: absolute;
top: 50%;
transform: translateY(-50%);
overflow: hidden;
}
Now, let's define the general attributes for all the image:
.carousel-image {
height: 20vh;
max-height: 200px;
position: absolute;
left: 50%;
border-radius: 7%;
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
}
Lastly, we specify each image position, z-index and brightness:
#carousel-image-0 {
transform: translateX(-50%) translateX(-120%) scale(0.6);
filter: brightness(40%);
z-index: 1;
}
#carousel-image-1 {
transform: translateX(-50%) translateX(-80%) scale(0.8);
filter: brightness(65%);
opacity: 1;
z-index: 2;
}
#carousel-image-2 {
transform: translateX(-50%) scale(1);
filter: brightness(100%);
opacity: 1;
z-index: 3;
}
#carousel-image-3 {
transform: translateX(-50%) translateX(80%) scale(0.8);
filter: brightness(65%);
opacity: 1;
z-index: 2;
}
#carousel-image-4 {
transform: translateX(-50%) translateX(120%) scale(0.6);
filter: brightness(40%);
opacity: 1;
z-index: 1;
}
#carousel-image-5 {
transform: translateX(-50%) scale(1.5);
filter: brightness(40%);
opacity: 0;
z-index: 1;
}
Here is the intermediate result:
We define an animation for each motion. For example, the following animation moves the image at position 0 (the image on the left) to the position 5 (the hidden image) :
@keyframes mv0to5 {
0% { transform: translateX(-50%) translateX(-120%) scale(0.6); filter: brightness(40%); opacity: 1; z-index: 2}
20% { opacity: 0; }
100% { transform: translateX(-50%) scale(0.6); filter: brightness(40%); opacity: 0; z-index:1}
}
In the same way, the following animation is the inverse of the previous one. It moves the image from the position 5 (the hidden image) to position 0 (the image on the left):
@keyframes mv5to0 {
0% { transform: translateX(-50%) scale(0.6); filter: brightness(40%); opacity: 0; z-index:1}
80% {opacity:0;}
100% { transform: translateX(-50%) translateX(-120%) scale(0.6); filter: brightness(40%); opacity: 1; z-index:2}
}
There are twelve animations, one for each image for each motion (forward and backward).
For each animation, we create a CSS class that perform the motion:
.mv0to5 {
animation: 0.3s ease-out mv0to5;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
To animate the carousel, just add the class to each images.
Of course, the animation is just performed once. To manage our carousel, we write a JavaScript class as follow:
// Class that manage the carousel
class Carousel {
// Constructor, initialise the carousel
constructor() {
// Set a new image (src) to image at given position (pos)
setImage(pos, src)
// Hide an image at given position (pos)
hideImage(pos)
// Show an image at given position (pos)
showImage(pos)
// Reset carousel, set image 2 in the middle
reset()
// Animate one image forward
next(nextImage)
// Animate one image backward
previous(previousImage) {
}
The constructor
// Constructor, initialise the carousel
constructor() {
// Get image elements
this.img = [];
this.img[0] = document.getElementById("carousel-image-0");
this.img[1] = document.getElementById("carousel-image-1");
this.img[2] = document.getElementById("carousel-image-2");
this.img[3] = document.getElementById("carousel-image-3");
this.img[4] = document.getElementById("carousel-image-4");
this.img[5] = document.getElementById("carousel-image-5");
// Set animation key frames forward and backward
this.animForward = ['mv0to5', 'mv1to0', 'mv2to1', 'mv3to2', 'mv4to3', 'mv5to4'];
this.animBackward = ['mv0to1', 'mv1to2', 'mv2to3', 'mv3to4', 'mv4to5', 'mv5to0'];
// Reset carousel
this.reset();
}
The reset()
function remove all the animations and set the main image (at position 2) on image 2:
// Reset carousel, set image 2 in the middle
reset() {
// Remove animations
this.img.forEach((image) => {
this.animForward.forEach((animation) => {
image.classList.remove( animation );
})
this.animBackward.forEach((animation) => {
image.classList.remove( animation );
})
})
this.currentImage=2;
}
The function next(nextImage)
animate the carousel one image forward.
It update the hidden image if requested, remove all animation classes before adding the new one.
Note that animation classes can be forward or backward depending on the last animation.
Here we remove both.
// Animate one image forward
// If nextImage is defined, replace the hidden image (at position 5) with the new image
next(nextImage) {
// Set new image if requested
if (nextImage !== undefined) this.setImage( 5 , nextImage );
// Animate
this.img.forEach((image, i) => {
// Remove animation
this.animForward.forEach((animation) => { image.classList.remove( animation ); });
this.animBackward.forEach((animation) => { image.classList.remove( animation ); });
// Animate to next image
image.classList.add( this.animForward[(-this.currentImage+i+8)%6] );
})
// Increase index to next image
this.currentImage = (this.currentImage+1)%6;
}
The function to animate backward is similar to the above.
We also added some function to hide, show or replace an image:
setImage(pos, src) {
this.img[(pos+this.currentImage+4)%6].src = src;
}
// Hide an image at given position (pos)
hideImage(pos) {
this.img[(pos+this.currentImage+4)%6].style.visibility = 'hidden';
}
// Show an image at given position (pos)
showImage(pos) {
this.img[(pos+this.currentImage+4)%6].style.visibility = 'visible';
}
Here is the final result: