How I made a simple lightbox with jQuery

I have been teaching myself to code through Treehouse and freeCodeCamp and this is one of my first projects using jQuery. In the front end web development path on Treehouse there is a section on jQuery and the teacher (Andrew Chalkley) shows you how to create a simple lightbox. This was my starting point but I took it a few steps further. You can check it out on CodePen here.

Goals for the project:

  1. Use Bootstrap to create a responsive image gallery
  2. Show a color overlay and icon when the user hovers over the image
  3. Open a responsive lightbox when the user clicks on the image
  4. Be able to browse through all the images in the lightbox

HTML

In this example, I am using CodePen as my text editor. I included the Bootstrap, Font Awesome, and jQuery files in my project.

<section id="gallery">
<div class="container">
<div id="image-gallery">
<div class="row">
<div class="col-lg-3 col-md-6 col-sm-6 col-xs-12 image">
<div class="img-wrapper">
<a href="https://unsplash.it/500"><img src="https://unsplash.it/500" class="img-responsive"></a>
<div class="img-overlay">
<i class="fa fa-plus-circle" aria-hidden="true"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 col-sm-6 col-xs-12 image">
<div class="img-wrapper">
<a href="https://unsplash.it/600"><img src="https://unsplash.it/600" class="img-responsive"></a>
<div class="img-overlay">
<i class="fa fa-plus-circle" aria-hidden="true"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 col-sm-6 col-xs-12 image">
<div class="img-wrapper">
<a href="https://unsplash.it/700"><img src="https://unsplash.it/700" class="img-responsive"></a>
<div class="img-overlay">
<i class="fa fa-plus-circle" aria-hidden="true"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 col-sm-6 col-xs-12 image">
<div class="img-wrapper">
<a href="https://unsplash.it/800"><img src="https://unsplash.it/800" class="img-responsive"></a>
<div class="img-overlay">
<i class="fa fa-plus-circle" aria-hidden="true"></i>
</div>
</div>
</div>
</div><!-- End row -->
</div><!-- End image gallery -->
</div><!-- End container -->
</section>

I have a section with an ID of “gallery” and inside it there is a div with the class of “container”. Then I have another div with the ID of “image-gallery” to wrap the gallery.

Inside each column is a div with the class of “img-wrapper”. I am using Unsplash It for the placeholder images. It’s important that the images link to themselves in order for the lightbox to work. The div with the class of “img-overlay” contains an icon that will appear when the user hovers over the image.

CSS

I originally wrote this in SCSS (Sassy CSS) but this has been compiled to CSS for easier reading. Sass is awesome by the way! I followed the mobile-first approach.

#gallery {
padding-top: 40px;
}
@media screen and (min-width: 991px) {
#gallery {
padding: 60px 30px 0 30px;
}
}

Just some padding for the section.

.img-wrapper {
position: relative;
margin-top: 15px;
}
.img-wrapper img {
width: 100%;
}

The div with the class of “img-wrapper” acts as a container for each image in the gallery. I set the position to relative in order for the overlay to show up properly. The margin will add some separation between the images. It’s important to set the width of the images to 100% in order for them to be responsive.

.img-overlay {
background: rgba(0, 0, 0, 0.7);
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
opacity: 0;
}
.img-overlay i {
color: #fff;
font-size: 3em;
}

This is all the styling for the color overlay that shows up when the user hovers over the image. I set the width and height to 100% and the position to absolute. I am using flexbox to center the icon horizontally and vertically. The opacity is initially set to 0. I will make it appear later with jQuery.

#overlay {
background: rgba(0, 0, 0, 0.7);
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
z-index: 999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#overlay img {
margin: 0;
width: 80%;
height: auto;
-o-object-fit: contain;
object-fit: contain;
padding: 5%;
}
@media screen and (min-width: 768px) {
#overlay img {
width: 60%;
}
}
@media screen and (min-width: 1200px) {
#overlay img {
width: 50%;
}
}
#nextButton {
color: #fff;
font-size: 2em;
-webkit-transition: opacity 0.8s;
transition: opacity 0.8s;
}
#nextButton:hover {
opacity: 0.7;
}
@media screen and (min-width: 768px) {
#nextButton {
font-size: 3em;
}
}
#prevButton {
color: #fff;
font-size: 2em;
-webkit-transition: opacity 0.8s;
transition: opacity 0.8s;
}
#prevButton:hover {
opacity: 0.7;
}
@media screen and (min-width: 768px) {
#prevButton {
font-size: 3em;
}
}
#exitButton {
color: #fff;
font-size: 2em;
-webkit-transition: opacity 0.8s;
transition: opacity 0.8s;
position: absolute;
top: 15px;
right: 15px;
}
#exitButton:hover {
opacity: 0.7;
}
@media screen and (min-width: 768px) {
#exitButton {
font-size: 3em;
}
}

This is all the styling for the lightbox. The overlay will create a semi-transparent box that takes up the entire screen. I set the width and height to 100% and the position to fixed. I used flexbox to center the image vertically and horizontally. I gave the overlay a z-index of 999 to make sure it will appear above all of the other elements. The user-select: none; hides the blue highlight on Chrome.

Next I styled the image inside the lightbox to be responsive. I included the height:auto; and object-fit: contain; to prevent stretching out the images in Firefox.

Finally, I styled the next, previous, and exit buttons for the lightbox. The buttons fade a little bit on hover. I am using the transition property to add some animation to the change in opacity.

JavaScript (jQuery)

Now to make the magic happen!

$( ".img-wrapper" ).hover(
function() {
$(this).find(".img-overlay").animate({opacity: 1}, 600);
}, function() {
$(this).find(".img-overlay").animate({opacity: 0}, 600);
}
);

When a user hovers over the image, it finds the div with the class of “img-overlay” and changes the opacity to 1. It will appear to fade in.

var $overlay = $('<div id="overlay"></div>');
var $image = $("<img>");
var $prevButton = $('<div id="prevButton"><i class="fa fa-chevron-left"></i></div>');
var $nextButton = $('<div id="nextButton"><i class="fa fa-chevron-right"></i></div>');
var $exitButton = $('<div id="exitButton"><i class="fa fa-times"></i></div>');

First, I created the jQuery objects for the lightbox: the overlay and the buttons.

$overlay.append($image).prepend($prevButton).append($nextButton).append($exitButton);
$("#gallery").append($overlay);

This code adds the overlay to the end of the div with the ID of “gallery”. If you are creating this HTML page from scratch in a text editor, you should append the overlay to the body.

$overlay.hide();

The overlay should be hidden by default.

$(".img-overlay").click(function(event) {
event.preventDefault();
var imageLocation = $(this).prev().attr("href");
$image.attr("src", imageLocation);
$overlay.fadeIn("slow");
});

This is a code for when a user clicks on the image overlay that appears on hover. First, event.preventDefault(); prevents the default behavior. Then the href attribute of the image is added to the variable imageLocation. Then the src attribute that matches imageLocation is added to $image. Finally, the overlay is faded in and shows the matching image that was clicked on.

$overlay.click(function() {
$(this).fadeOut("slow");
});

Whenever the overlay is clicked, it fades out.

$nextButton.click(function(event) {
$("#overlay img").hide();
var $currentImgSrc = $("#overlay img").attr("src");
var $currentImg = $('#image-gallery img[src="' + $currentImgSrc + '"]');
var $nextImg = $($currentImg.closest(".image").next().find("img"));
var $images = $("#image-gallery img");
if ($nextImg.length > 0) {
$("#overlay img").attr("src", $nextImg.attr("src")).fadeIn(800);
} else {
$("#overlay img").attr("src", $($images[0]).attr("src")).fadeIn(800);
}
event.stopPropagation();
});

This code allows the user to click on a button and view the next image. The code block runs when $nextButton is clicked. First, the current image is hidden. Then we need to find the overlay image location and store it in the variable $currentImgSrc. Then we need the image that matches the location of the overlay image and store it in the variable $currentImg. Then we find the next image and store it in the variable $nextImg. Next, I created a jQuery object representing all of the images in the gallery and stored in it the variable $images. The next part of the code is an if else statement. If there is a next image, then fade in the next image. Otherwise, fade in the first image. The last part prevents the overlay from being hidden.

$prevButton.click(function(event) {
$("#overlay img").hide();
var $currentImgSrc = $("#overlay img").attr("src");
var $currentImg = $('#image-gallery img[src="' + $currentImgSrc + '"]');
var $nextImg = $($currentImg.closest(".image").prev().find("img"));
$("#overlay img").attr("src", $nextImg.attr("src")).fadeIn(800);
event.stopPropagation();
});

This code block is similar to when the next button is clicked. The difference is that it finds the previous image instead of the next image. I added a class of “image” to the parent div of “img-wrapper” to make it a little easier. You may use a function here if you prefer.

$exitButton.click(function() {
$("#overlay").fadeOut("slow");
});

Finally, this code fades out the overlay when the exit button is clicked. Thank you for reading about my first jQuery project!