Create Functional Image Gallery in HTML CSS & JavaScript

Create Functional Image Gallery in HTML CSS & JavaScript

If you’re a web designer or developer, you must have searched for copyright-free images for your projects on various websites. Pexels is one of the most popular sites for such images. But as a web developer, have you ever wanted to create a functional image gallery similar to Pexels?

In this blog post, I’ll show the steps for creating a fully-functional image gallery using HTML, CSS, and JavaScript. Not only will you learn the basics of DOM manipulation, event handling, and CSS styling, but you’ll also gain valuable experience working with APIs.

With this Pexels clone coding project, you can effortlessly search, view, and download any image you desire, all within seconds. The images are displayed in a stylish masonry layout which looks great on any device, from desktops to mobile phones.

If you’re excited to see a live demo of this image gallery, click here to check it out. For a full video tutorial on creating a functional image gallery using HTML, CSS, and JavaScript, you can watch the given YouTube video.

Video Tutorial of Functional Image Gallery in JavaScript

If you prefer visual learning, then the above video tutorial is a great resource for you. I highly recommend watching it because I go through each line of code in detail and provide comments to help you understand what’s happening at each step.

But if you prefer reading blog posts or want a quick summary of the steps involved in creating an image gallery, you can continue reading this post. By the end of this post, you will have a clear understanding of how to create your very own Pexels clone image gallery with HTML, CSS, and JavaScript.

Steps For Creating Image Gallery in JavaScript

To create a functional image gallery using HTML, CSS, and vanilla JavaScript, follow the given steps line by line:

  1. Create a folder. You can name this folder whatever you want, and inside this folder, create the mentioned files.
  2. Create an index.html file. The file name must be index and its extension .html
  3. Create a style.css file. The file name must be style and its extension .css
  4. Create a script.js file. The file name must be script and its extension .js
  5. Download the images folder from Google Drive and put this folder inside the project folder. This static image is only used as a search section background.

To start, add the following HTML codes to your index.html file to create a basic layout for an image gallery. Note that the “ul” container is currently empty, but it will be filled with “li” elements (representing image cards) later using JavaScript code.

<!DOCTYPE html>
<!-- Coding By CodingNepal - youtube.com/codingnepal -->
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Image Gallery with JavaScript | CodingNepal</title>
    <link rel="stylesheet" href="style.css">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.0/css/line.css">
    <script src="script.js" defer></script>
  </head>
  <body>
    <div class="lightbox">
      <div class="wrapper">
        <header>
          <div class="photographer">
            <i class="uil uil-camera"></i>
            <span></span>
          </div>
          <div class="buttons">
            <i class="uil uil-import"></i>
            <i class="close-icon uil uil-times"></i>
          </div>
        </header>
        <div class="preview-img">
          <div class="img"><img src="" alt="preview-img"></div>
        </div>
      </div>
    </div>
    <section class="search">
      <img src="./images/search-img.jpg" alt="search-img">
      <div class="content">
        <h1>Image Gallery with JavaScript</h1>
        <p>Search and download any images within a second</p>
        <div class="search-box">
          <i class="uil uil-search"></i>
          <input type="text" placeholder="Search images">
        </div>
      </div>
    </section>
    <section class="gallery">
      <ul class="images"></ul>
      <button class="load-more">Load More</button>
    </section>

  </body>
</html>

Next, add the following CSS codes to your style.css file to give a basic look and feel to the image gallery. If you wish, you can customize it to your liking by changing the color, font, size, and other CSS properties in the file.

/* Import Google font - Poppins */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Poppins", sans-serif;
}
.search {
  height: 40vh;
  display: flex;
  position: relative;
  align-items: center;
  justify-content: center;
}
.search::before, .search img, .lightbox {
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  position: absolute;
}
.search::before {
  content: "";
  z-index: 1;
  background: rgba(0,0,0,0.25);
}
.search img {
  object-fit: cover;
}
.search .content {
  z-index: 2;
  color: #fff;
  padding: 0 13px;
  text-align: center;
  position: relative;
}
.search h1 {
  font-size: 2.65rem;
  font-weight: 600;
}
.search p {
  margin-top: 8px;
  font-size: 1.5rem;
}
.search .search-box {
  height: 55px;
  margin: 45px 0;
  position: relative;
}
.search-box i {
  position: absolute;
  left: 20px;
  top: 50%;
  cursor: default;
  color: #8D8D8D;
  font-size: 1.4rem;
  transform: translateY(-50%);
}
.search-box input {
  width: 100%;
  height: 100%;
  outline: none;
  border: none;
  font-size: 1.1rem;
  padding-left: 55px;
  background: #fff;
  border-radius: 5px;
}
.search-box input::placeholder {
  color: #929292;
}
.search-box input:focus::placeholder {
  color: #bfbfbf;
}
.gallery {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.gallery .images {
  gap: 15px;
  max-width: 95%;
  margin-top: 40px;
  columns: 5 340px;
  list-style: none;
}
.gallery .images .card {
  display: flex;
  cursor: pointer;
  overflow: hidden;
  position: relative;
  margin-bottom: 14px;
  border-radius: 4px;
}
.gallery .images img {
  width: 100%;
  z-index: 2;
  position: relative;
}
.images .details {
  position: absolute;
  z-index: 4;
  width: 100%;
  bottom: -100px;
  display: flex;
  align-items: center;
  padding: 15px 20px;
  justify-content: space-between;
  transition: bottom 0.1s ease;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
}
.images li:hover .details {
  bottom: 0;
}
.photographer {
  color: #fff;
  display: flex;
  align-items: center;
}
.photographer i {
  font-size: 1.4rem;
  margin-right: 10px;
}
.photographer span {
  font-size: 1.05rem;
}
button, i {
  outline: none;
  border: none;
  cursor: pointer;
  border-radius: 5px;
  transition: 0.2s ease;
}
.details button {
  background: #fff;
  font-size: 1.1rem;
  padding: 3px 8px;
}
.details .download-btn:hover {
  background: #f2f2f2;
}
.gallery .load-more {
  color: #fff;
  background: #8A6CFF;
  margin: 50px 0;
  font-size: 1.2rem;
  padding: 12px 27px;
}
.gallery .load-more.disabled {
  opacity: 0.6;
  pointer-events: none;
}
.gallery .load-more:hover {
  background: #704dff;
}

.lightbox {
  z-index: 5;
  position: fixed;
  visibility: hidden;
  background: rgba(0,0,0,0.65);
}
.lightbox.show {
  visibility: visible;
}
.lightbox .wrapper {
  position: fixed;
  left: 50%;
  top: 50%;
  width: 100%;
  padding: 20px;
  max-width: 850px;
  background: #fff;
  border-radius: 6px;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0.9);
  transition: transform 0.1s ease;
}
.lightbox.show .wrapper {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, -50%) scale(1);
}
.wrapper header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
header .photographer {
  color: #333;
}
header .photographer i {
  font-size: 1.7rem;
  cursor: auto;
}
header .photographer span {
  font-size: 1.2rem;
}
header .buttons i {
  height: 40px;
  width: 40px;
  display: inline-block;
  color: #fff;
  font-size: 1.2rem;
  line-height: 40px;
  text-align: center;
  background: #8A6CFF;
  border-radius: 4px;
  transition: 0.2s ease;
}
header .buttons i:first-child:hover {
  background: #704dff;
}
header .buttons i:last-child {
  margin-left: 10px;
  font-size: 1.25rem;
  background: #6C757D;
}
header .buttons i:last-child:hover {
  background: #5f666d;
}
.wrapper .preview-img {
  display: flex;
  justify-content: center;
  margin-top: 25px;
}
.preview-img .img {
  max-height: 65vh;
}
.preview-img img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

@media screen and (max-width: 688px) {
  .lightbox .wrapper {
    padding: 12px;
    max-width: calc(100% - 26px);
  }
  .wrapper .preview-img {
    margin-top: 15px;
  }
  header .buttons i:last-child {
    margin-left: 7px;
  }
  header .photographer span, .search p {
    font-size: 1.1rem;
  }
  .search h1 {
    font-size: 1.8rem;
  }
  .search .search-box {
    height: 50px;
    margin: 30px 0;
  }
  .gallery .images {
    max-width: 100%;
    padding: 0 13px;
    margin-top: 20px;
  }
  .images .details {
    bottom: 0px;
  }
  .gallery .load-more {
    padding: 10px 25px;
    font-size: 1.05rem;
  }
}

Finally, add the following JavaScript code to your script.js file to add functionality for searching, viewing, and downloading images from this gallery. This code will handle user actions and communicate with the Pexels API to retrieve and display images in the gallery.

const imageWrapper = document.querySelector(".images");
const searchInput = document.querySelector(".search input");
const loadMoreBtn = document.querySelector(".gallery .load-more");
const lightbox = document.querySelector(".lightbox");
const downloadImgBtn = lightbox.querySelector(".uil-import");
const closeImgBtn = lightbox.querySelector(".close-icon");

// API key, paginations, searchTerm variables
const apiKey = "PASTE-YOUR-API-KEY";
const perPage = 15;
let currentPage = 1;
let searchTerm = null;

const downloadImg = (imgUrl) => {
    // Converting received img to blob, creating its download link, & downloading it
    fetch(imgUrl).then(res => res.blob()).then(blob => {
        const a = document.createElement("a");
        a.href = URL.createObjectURL(blob);
        a.download = new Date().getTime();
        a.click();
    }).catch(() => alert("Failed to download image!"));
}

const showLightbox = (name, img) => {
    // Showing lightbox and setting img source, name and button attribute
    lightbox.querySelector("img").src = img;
    lightbox.querySelector("span").innerText = name;
    downloadImgBtn.setAttribute("data-img", img);
    lightbox.classList.add("show");
    document.body.style.overflow = "hidden";
}

const hideLightbox = () => {
    // Hiding lightbox on close icon click
    lightbox.classList.remove("show");
    document.body.style.overflow = "auto";
}

const generateHTML = (images) => {
    // Making li of all fetched images and adding them to the existing image wrapper
    imageWrapper.innerHTML += images.map(img =>
        `<li class="card">
            <img onclick="showLightbox('${img.photographer}', '${img.src.large2x}')" src="${img.src.large2x}" alt="img">
            <div class="details">
                <div class="photographer">
                    <i class="uil uil-camera"></i>
                    <span>${img.photographer}</span>
                </div>
                <button onclick="downloadImg('${img.src.large2x}');">
                    <i class="uil uil-import"></i>
                </button>
            </div>
        </li>`
    ).join("");
}

const getImages = (apiURL) => {
    // Fetching images by API call with authorization header
    searchInput.blur();
    loadMoreBtn.innerText = "Loading...";
    loadMoreBtn.classList.add("disabled");
    fetch(apiURL, {
        headers: { Authorization: apiKey }
    }).then(res => res.json()).then(data => {
        generateHTML(data.photos);
        loadMoreBtn.innerText = "Load More";
        loadMoreBtn.classList.remove("disabled");
    }).catch(() => alert("Failed to load images!"));
}

const loadMoreImages = () => {
    currentPage++; // Increment currentPage by 1
    // If searchTerm has some value then call API with search term else call default API
    let apiUrl = `https://api.pexels.com/v1/curated?page=${currentPage}&per_page=${perPage}`;
    apiUrl = searchTerm ? `https://api.pexels.com/v1/search?query=${searchTerm}&page=${currentPage}&per_page=${perPage}` : apiUrl;
    getImages(apiUrl);
}

const loadSearchImages = (e) => {
    // If the search input is empty, set the search term to null and return from here
    if (e.target.value === "") return searchTerm = null;
    // If pressed key is Enter, update the current page, search term & call the getImages
    if (e.key === "Enter") {
        currentPage = 1;
        searchTerm = e.target.value;
        imageWrapper.innerHTML = "";
        getImages(`https://api.pexels.com/v1/search?query=${searchTerm}&page=1&per_page=${perPage}`);
    }
}

getImages(`https://api.pexels.com/v1/curated?page=${currentPage}&per_page=${perPage}`);
loadMoreBtn.addEventListener("click", loadMoreImages);
searchInput.addEventListener("keyup", loadSearchImages);
closeImgBtn.addEventListener("click", hideLightbox);
downloadImgBtn.addEventListener("click", (e) => downloadImg(e.target.dataset.img));

In the code, you will notice a variable called apiKey. You need to get your own Pexels API key and insert it into this variable. You can get a free API key by visiting the official Pexels API documentation. Additionally, you will find a variable named perPage, which has a default value of 15. This means that every time the API is called, 15 new images will be fetched.

Conclusion and Final Words

Creating a functional image gallery using HTML, CSS, and JavaScript is an excellent project for beginners to learn about web development concepts such as DOM manipulation, event handling, CSS styling, and API usage in real-world projects.

With the knowledge and skills you’ve gained from this project, now it’s up to you to experiment with the code and take this image gallery to the next level. For more API-related coding projects, check out the blog on Top JavaScript APIs Projects for Beginners.

If you encounter any problems or your code is not working as expected, you can download the source code files for this image gallery for free. Click on the download button to get the zip file containing the project folder with source code files. Remember to paste your API key into the code.

 

Previous articleHow to create Pagination in HTML CSS & JavaScript
Next articleWebsite with Login & Registration Form in HTML CSS & JavaScript