Multiple Image Galleries in a Single Page using ES6 JavaScript
Friday, August 6, 2021 Posted in Web-DevelopmentTags : JavaScript HTML5 CSS3
Ever wondered how to create and embed many Image Slideshows into a single web page? This post shows you how!
In my previous post about Linked List, I needed to add multiple image galleries into it for the purose of showing step by step diagrams of each Linked List operation, however, the code I already had written was good for only a single Image Gallery, so I successfuly reworked that code into an ES6 Class to make it reusable across a single web page, to create multiple independent image galleries, In this post, I will share and explain that code to you
Starting out with HTML
We will implement our Image Gallery with simple HTLM5, ES6 JS and CSS3, no fancy libraries will be used for this. Our Image Gallery will have a counter on the top-left, the usual arrows to move to the next or previous image, a counter to show which image you are currently on, and each image will have a caption, now that this is out of the way, we can start out with the HTML skeleton of our image gallery.
The below code snippet just contains the first image gallery, the rest of the HTML has been elided for brevity a more complete version of the HTML can be found on either the CodePen of this code or on it’s GitHub respository, both of which are linked to in the end of this article.
<div class="container">
<div id="first" class="gallery-container">
<div class="mySlides" style="display: block;">
<div class="numbertext">1 / 3</div>
<div class="fullscreen-btn" onclick="ImageGallery.toggleFullscreenImage('https://cdn.pixabay.com/photo/2020/05/15/14/03/lake-5173683_960_720.jpg')" src="https://cdn.pixabay.com/photo/2020/05/15/14/03/lake-5173683_960_720.jpg')"><i class="fas fa-expand"></i></div>
<img class="imgSlide" onclick="ImageGallery.toggleFullscreenImage('https://cdn.pixabay.com/photo/2020/05/15/14/03/lake-5173683_960_720.jpg')" src="https://cdn.pixabay.com/photo/2020/05/15/14/03/lake-5173683_960_720.jpg" style="width:100%" >
<div class="caption-container">
<p id="caption"> Drying Lake </p>
</div>
</div>
<div class="mySlides" style="display: none;">
<div class="numbertext">2 / 3</div>
<div class="fullscreen-btn" onclick="ImageGallery.toggleFullscreenImage('https://cdn.pixabay.com/photo/2018/08/12/16/59/ara-3601194_960_720.jpg')"><i class="fas fa-expand"></i></div>
<img class="imgSlide" onclick="ImageGallery.toggleFullscreenImage('https://cdn.pixabay.com/photo/2018/08/12/16/59/ara-3601194_960_720.jpg')" src="https://cdn.pixabay.com/photo/2018/08/12/16/59/ara-3601194_960_720.jpg" style="width:100%" >
<div class="caption-container">
<p id="caption"> Colorful Parrot </p>
</div>
</div>
<div class="mySlides" style="display: none;">
<div class="numbertext">3 / 3</div>
<div class="fullscreen-btn" onclick="ImageGallery.toggleFullscreenImage('https://cdn.pixabay.com/photo/2014/02/27/16/10/tree-276014_960_720.jpg')"><i class="fas fa-expand"></i></div>
<img class="imgSlide" onclick="ImageGallery.toggleFullscreenImage('https://cdn.pixabay.com/photo/2014/02/27/16/10/tree-276014_960_720.jpg')" src="https://cdn.pixabay.com/photo/2014/02/27/16/10/tree-276014_960_720.jpg" style="width:100%" >
<div class="caption-container">
<p id="caption"> Flowers & Grass </p>
</div>
</div>
<a class="prev">❮</a>
<a class="next">❯</a>
</div>
</div>
In the above code we have a main div with the class container
, In this div sits all your content, i.e the text and image galleries, and the CSS class container just centers its content and limits the width to about 50% wide.
The next div has an id of first
and a class of gallery-container
, this is the div which is basically our first image gallery, and another seperate image gallery can be made just like this with just the id changed from first
to something else, in the JS code we will write, the id is the unique identifier for this image gallery.
<div class="mySlides" style="display: block;">
<div class="numbertext">1 / 3</div>
<div class="fullscreen-btn" onclick="ImageGallery.toggleFullscreenImage('https://cdn.pixabay.com/photo/2020/05/15/14/03/lake-5173683_960_720.jpg')" src="https://cdn.pixabay.com/photo/2020/05/15/14/03/lake-5173683_960_720.jpg')"><i class="fas fa-expand"></i></div>
<img class="imgSlide" onclick="ImageGallery.toggleFullscreenImage('https://cdn.pixabay.com/photo/2020/05/15/14/03/lake-5173683_960_720.jpg')" src="https://cdn.pixabay.com/photo/2020/05/15/14/03/lake-5173683_960_720.jpg" style="width:100%" alt=" tail.next = newNode; ">
<div class="caption-container">
<p id="caption"> A Lake of some kind </p>
</div>
</div>
Inside our gallery-container
, we have the mySlides
div, which is a single Image slide, this contains the number of the image, a fullscreen button, the Image itself, and a seperate container for the image’s caption, for each image you will have many such mySlides
divs in your gallery-container
image gallery.
I highly recommend to use a templating engine to create these mySlide
divs in a loop from arrays with the Image src and caption text provided, like I have done with my Linked List Blog Post’s image slides, these divs can also be created using JS, but I will not be getting into that.
ES6 JavaScript to make it work
The way our multiple Image Galleries or slideshows will work, is every Image gallery container div in a given page will have a unique id
, which the JS code will use to lock into that specific div container and perform the operations within, like showing previous/next image, making an image fullscreen etc, we will supply the id to the constructor
function of this JS Class and also name the object that the constructor instantiates as the same as the id provided.
let first = new ImageGallery("first");
In the next line we see the code for our ImageGallery
class and it’s constructor.
class ImageGallery {
constructor(id) {
this.container = document.getElementById(id);
this.prevButton = this.container.querySelector(".prev");
this.nextButton = this.container.querySelector(".next");
this.slideIndex = 1;
var that = this;
this.showSlide(this.slideIndex);
this.prevButton.addEventListener("click", function () {
that.advanceSlide(-1);
});
this.nextButton.addEventListener("click", function () {
that.advanceSlide(1);
});
}
}
let first = new ImageGallery("first");
In the first line of code we take in the id provided as a parameter to the constructor, and use it to find a div with a matching id using document.getElemendById(id)
, now this div contains our Image gallery, it’s slides and its previous and next buttons, so we create a class property this.prevButton
and assign it the element found by matching the .prev
class inside this.container
using this.container.querySelector(".prev")
, we do the same thing for the this.nextButton
, we set another property slideIndex
to 1, the slideIndex
property is what controls which image is to be displayed according to it’s numerical position among other images in the gallery.
We then initialize the this.showSlide
function which will be implemented later on, this shows the first image slide in the gallery, we then add onClick Event Listeners to both the this.prevButton
and this.nextButton
, so when a user clicks on either of these buttons, the this.advanceSlide()
function is called, with -1 if prevButton is clicked to show the previous image, or 1 if nextButton is clicked to show the next image.
Now that we are done with our constructor, we will see the showSlide
and advanceSlide
methods, these must be inside the ImageGallery
class, and i’ve elided the constructor that we have already seen in detail.
class ImageGallery {
advanceSlide = function (n) {
this.showSlide((this.slideIndex += n));
};
showSlide = function (n) {
var slide = this.container.getElementsByClassName("imageSlide");
if (n > slide.length) {
this.slideIndex = 1;
}
if (n < 1) {
this.slideIndex = slide.length;
}
for (var i = 0; i < slide.length; i++) {
slide[i].style.display = "none";
}
slide[this.slideIndex - 1].style.display = "block";
};
}
As you can see, advanceSlide is a wrapper function around this.showSlide
, the parameter it supplies is assigned to the this.slideIndex
and is this.slideIndex
current value plus the parameter n
, for e.g if there are 7 images in the gallery, and the slideIndex
is set to 4, a click on prevButton
will turn n
to -1, which when added to 4 will be 3, decreasing the slideIndex, and this.showSlide()
will then show the 3rdimage.
Next up is showSlide()
, this controls the back and forth functionality of our image gallery, first we get an array of all the image divs that have the className imageSlide
using var slide = this.container.getEelementsByClassName("imageSlide")
, this gets the image div array and stored it in var slide
.
The following if statements are to create wrap-around functionality, if the n
provided is lesser than 1 or greater than the length of the slide
array, if the n
is lesser, like say 0 or -1, the slideIndex
is set to 1, if the n
is greater for e.g 8 or 9 than the slide.length
that is say 7, the slideIndex is set to the slide.length
, i.e the last image in the array.
We then have a for loop to hide every div in the slide
array by setting it’s CSS display
property to none
, and then we pick our the image div element from the slide
array using the this.slideIndex
and display it by setting the CSS display
property to block
.
Now there is one last function to take care off, this is the toggleFunscreenImage()
method given below, as before, previously explained functions are not shown for brevity.
class ImageGallery {
static toggleFullscreenImage(imagename = null) {
var fullscreenDisplayDiv = document.getElementById("fullscreen-display");
var img = fullscreenDisplayDiv.getElementsByTagName("img");
var close = fullscreenDisplayDiv.getElementsByTagName("i");
if(imagename != null) {
img[0].setAttribute("src", "/public/assets/images/" + imagename + ".png");
close[0].style.display = "block";
fullscreenDisplayDiv.className = "fullscreen-display-show";
window.document.body.style.overflow = "hidden";
} else {
img[0].setAttribute("src", " ");
close[0].style.display = "none";
fullscreenDisplayDiv.className = "fullscreen-display-hide";
window.document.body.style.overflow = "auto";
}
}
}
How this works is there is a hidden div on your page with the id of fullscreen-display
, and every image in every one of your galleries has a Fullscreen icon button, this button upon being clicked calls the toggleFullscreenImage()
function with the src
of the image as the parameter, this src is then set to the img div inside the fullscreen-display
div and this div is then un-hidden, and because of CSS classes it uses, goes fullscreen with the provided image, in this fullscreen div, a red X button is provided to close it, which calls the same toggleFullscreenImage()
button but without any parameters.
Since that’s out of the way, we now explain the implementation, You will notice the toggleFullscreenImage
method is marked as static
which means that this specific function can be called without instantiation as an object, the next thing is the imagename = null
as the parameter, this is a default parameter, which means if nothing is specified for imagename
i.e the function is called without any parameters, set the imagename
parameter to null
.
We then get the fullscreenDisplayDiv using document.getElementById("fullscreen-display");
, remember this is the hidden div that will go fullscreen with the provided image when the fullscreen button is clicked.
The next vars, img
and close
are the image tag that will be displayed fullscreen and the red X button to close the fullscreen.
The if else block that comes next either opens the fullscreen or closes it, depending if imagename
is null or not, if it is not and an image name is specified, the src
attribute of the img
is set to the imagename
, the red X button represented by the close
var is unhidden by setting it’s display to block
, the fullscreen display div is revealed by chanding it’s class to fullscreen-display-show
and the scrolling of the page is disabled using window.document.body.style.overflow = "hidden"
.
The Else part of the block does the opposite, which is triggered when the imagename
is null, i.e the user has clicked the close button in the fullscreen mode.
CSS Styling
Of course our Image Gallery just wouldn’t work without the proper CSS styling and neither would the fullscreen functionality, so here it is.
:root {
--main-blk-color: #25282b;
scroll-behavior: smooth;
}
.mySlides {
display: none;
}
.mySlides img {
margin:0!important;
}
.gallery-container {
position: relative;
border:5px solid var(--main-blk-color);
}
.caption-container {
text-align: center;
background-color: var(--main-blk-color);
padding: 2px 16px;
}
imgSlide img {
display:block;
}
.prev,
.next {
cursor: pointer;
position: absolute;
top: 40%;
width: auto;
padding: 16px;
margin-top: -50px;
color: white;
font-weight: bold;
font-size: 20px;
border-radius: 0 3px 3px 0;
user-select: none;
-webkit-user-select: none;
background-color: rgba(0, 0, 0, 0.5);
}
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
.prev:hover,
.next:hover {
background-color: rgba(0, 0, 0, 0.8);
}
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
background-color: rgba(0, 0, 0, 0.5);
}
#caption {
color: white!important;
margin: 1rem auto;
}
.container, p, h1 {
width:50%;
margin:auto;
}
p {
font-size:20px;
padding:1rem 0;
}
h1 {
padding:2rem 0;
font-size: 40px;
text-align:center;
}
.fullscreen-btn {
color: #f2f2f2;
font-size: 24px;
padding: 8px 12px;
position: absolute;
cursor:pointer;
top: 0;
right:0;
background-color: rgba(0, 0, 0, 0.5);
}
.fullscreen-display-hide {
display:none;
}
.fullscreen-display-hide i {
display:none;
}
.fullscreen-display-show {
position:fixed; /* takes up whole viewport */
left:0; /*snaps div to left*/
top:0;/*snaps div to left*/
display:flex;
z-index:1000;
width: 100%;
height:100%;
background-color:rgba(0, 0, 0, 0.9);
}
.fullscreen-display-show img {
height: fit-content;
margin:auto!important
}
.fullscreen-display-show i {
display: block;
font-size: 3rem;
color:white;
cursor:pointer;
padding:1rem 1.5rem;
background-color:#dc3545!important;
height: fit-content;
border-radius: 10px;
margin:0.5rem;
position:absolute;
right:0;
}
Conclusion.
That’s a wrap, I hope you’ve learned much from this little post, a live demo of this code is available on my CodePen, and the rest of the code including the CSS is on GitHub, as mentioned earlier, you will probably need to write either a JavaScript generator function or use a templating engine( i’m using Jekyll’s Liquid templating engine btw ) for the grunt work of creating the imageSlide
divs with their counters, image with src and caption, so good luck with that.
The CodePen is embedded below for convinience, but it looks better when opened in it’s own tab.
See the Pen by Shawn D'silva (@shade97) on CodePen.