Creating an Image Gallery Grid View with Preview Modal using HTML, CSS, and JS Tutorial

In this Tutorial, you can learn how to create a creative and responsive Grid View of an Image Gallery with Preview Modal for websites using HTML, CSS, and JavaScript. The tutorial aims to provide students and beginners with a reference for learning to create a creative, interactive, and responsive website UI and component. Here, I will be providing a sample website page script that demonstrates the main goal of this tutorial. The complete source code zip file will also be provided and it is free to download.

What is Image Gallery?

An Image Gallery is a page of a website that contains some relevant images stored on the site. It is a common way of integrating images into websites that display multiple images at once. It is also often implemented with a preview modal that allows the users to view the image on a larger scale.

How to Create an Image Gallery Grid View with Preview Modal?

The Image Gallery Grid View with Preview Modal can be achieved using HTML, CSS, and JavaScript without using any other JS Libraries. Using HTML, we display the gallery images using some HTML elements such as div and img tags. The CSS will help us to design the gallery wrapper to be responsive and display the images in grid view. Also, we can design the Preview Modal using some CSS properties. Then, using JavaScript, we can create the preview modal and other elements functional. Check out the simple web page scripts that I created and provided below to have a better understanding.

Sample Web Page Scripts

The following scripts result in a simple website page that contains an Image Gallery that is shown in a Grid View. The Gallery Grid is responsive to any device screen such as mobiles and desktops. The web page contains also a Preview modal that displays the selected image on a larger scale. The modal also contains a navigation button to simply navigate to the previous or next image without closing the Preview Modal.

HTML

Here's the HTML file script known as index.html. The file contains the relevant elements to the website page including the Image Gallery and Preview Modal. The images I used on the script below are included in the source code zip file.

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.     <meta charset="UTF-8">
  4.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  5.     <title>Simple Gallery Grid View with Viewer</title>
  6.     <link rel="stylesheet" href="style.css">
  7.     <link rel="preconnect" href="https://fonts.googleapis.com">
  8.     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  9.     <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,[email protected],100..700,0..1,-50..200" />
  10. </head>
  11.     <div class="container">
  12.         <h1 id="page-title">Simple Gallery Grid View with Viewer using HTML, CSS, and JS</h1>
  13.         <hr id="title_hr">
  14.         <div id="gallery-wrapper">
  15.             <div class="gallery-item">
  16.                 <img src="./images/image-1.jpg" alt="Photo By: Dids from pixels.com">
  17.             </div>
  18.             <div class="gallery-item">
  19.                 <img src="./images/image-2.jpeg" alt="Photo By: Karolina Grabowska from pixels.com">
  20.             </div>
  21.             <div class="gallery-item">
  22.                 <img src="./images/image-3.jpg" alt="Photo By: Karolina Grabowska from pixels.com">
  23.             </div>
  24.             <div class="gallery-item">
  25.                 <img src="./images/image-4.jpg" alt="Photo By: Brett Jordan from pixels.com">
  26.             </div>
  27.             <div class="gallery-item">
  28.                 <img src="./images/image-5.jpg" alt="Photo By: Bruno Cervera from pixels.com">
  29.             </div>
  30.             <div class="gallery-item">
  31.                 <img src="./images/image-6.jpg" alt="Photo By: Alexander Ant from pixels.com">
  32.             </div>
  33.             <div class="gallery-item">
  34.                 <img src="./images/image-7.jpg" alt="Photo By: Pixabay from pixels.com">
  35.             </div>
  36.             <div class="gallery-item">
  37.                 <img src="./images/image-2.jpeg" alt="Photo By: Karolina Grabowska from pixels.com">
  38.             </div>
  39.             <div class="gallery-item">
  40.                 <img src="./images/image-8.jpg" alt="Photo By: Tim Gouw from pixels.com">
  41.             </div>
  42.             <div class="gallery-item">
  43.                 <img src="./images/image-1.jpg" alt="Photo By: Dids from pixels.com">
  44.             </div>
  45.             <div class="gallery-item">
  46.                 <img src="./images/image-6.jpg" alt="Photo By: Alexander Ant from pixels.com">
  47.             </div>
  48.         </div>
  49.     </div>
  50.     <div id="preview">
  51.         <div id="preview-body">
  52.             <div id="preview-img">
  53.                 <img  src="./images/image-6.jpg" alt="Preview Image">
  54.             </div>
  55.             <button class="preview-close"><span aria-hidden="true">&times;</span></button>
  56.             <button class="previous-btn"><span aria-hidden="true">&lt;</span></button>
  57.             <button class="next-btn"><span aria-hidden="true">&gt;</span></button>
  58.         </div>
  59.     </div>
  60.     <script src="script.js"></script>
  61. </body>
  62. </html>

CSS

Next, here's the CSS file script known as style.css. It contains the stylesheet codes that design the application page layout and other elements.

  1. @import url('https://fonts.googleapis.com/css2?family=Dongle:wght@300;400;700&family=Roboto+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;1,100;1,200;1,300;1,400;1,500;1,600&display=swap" rel="stylesheet');
  2. *{
  3.     margin: 0;
  4.     padding: 0;
  5.     box-sizing: border-box;
  6.     font-family: 'Dongle', sans-serif;
  7.     font-family: 'Roboto Mono', monospace;
  8. }
  9. ::selection{
  10.     color: #fff;
  11.     background: #4db2ec;
  12. }
  13. body{
  14.     display: flex;
  15.     align-items: center;
  16.     justify-content: center;
  17.     min-height: 100vh;
  18.     background: #4facfe;
  19.     background-image: linear-gradient(to right, #4facfe 0%, #00f2fe 100%);
  20.     padding: 2em 0;
  21. }
  22. #page-title{
  23.     color: #fff;
  24.     text-align: center;
  25.     font-weight: 500;
  26.     text-shadow: 0px 0px 15px #0000003a;
  27. }
  28. #title_hr{
  29.     width:60px;
  30.     border: 2px solid #ffffff;
  31.     margin: .35em auto;
  32. }
  33. @media (min-width: 780px){
  34.     #page-title{
  35.     width: 780px;
  36.     }
  37. }
  38. #gallery-wrapper {
  39.     width: 780px;
  40.     position: relative;
  41.     grid-gap: 10px;
  42.     margin: 2em auto;
  43.     display: grid;
  44.     grid-template-columns: repeat(4, 24%);
  45.     grid-auto-rows: minmax(50px, 100px);
  46.     grid-auto-flow: dense;
  47.     display: none;
  48. }
  49.  
  50. .gallery-item {
  51.     width: calc(33.33% - 30px);
  52.     width: 100%;
  53.     overflow: hidden;
  54.     float: left;
  55.     cursor: pointer;
  56. }
  57.  
  58. .gallery-item img {
  59.     width: 100%;
  60.     height: 100%;
  61.     object-fit: cover;
  62.     object-position: center center;
  63.     transition: all .2s ease;
  64. }
  65. .gallery-item:hover img {
  66.     transform: scale(1.2);
  67. }
  68.  
  69. .gallery-item[data-display="portrait"] {
  70.     grid-row: span 2;
  71. }
  72. .gallery-item[data-display="landscape"] {
  73.     grid-column: span 2;
  74.     grid-row: span 2;
  75. }
  76.  
  77. @media (max-width:800px){
  78.     #gallery-wrapper{
  79.     width: 95%;
  80.     grid-template-columns: repeat(2, 49%) !important;
  81.     }
  82. }
  83.  
  84. div#preview {
  85.     position: fixed;
  86.     width: 100%;
  87.     height: 100%;
  88.     top: 0;
  89.     left: 0;
  90.     background: #000000d9;
  91.     display: flex;
  92.     align-items: center;
  93.     justify-content: center;
  94.     transition: all .3s ease;
  95.     transform: scale(0);
  96.     filter: blur(15px);
  97. }
  98. div#preview.show{
  99.     transform: scale(1);
  100.     filter: unset;
  101. }
  102. div#preview-body {
  103.     position: relative;
  104.     width: 700px;
  105.     height: 600px;
  106. }
  107. div#preview-img {
  108.     width: 100%;
  109.     height: 100%;
  110.     overflow: hidden;
  111.     background: linear-gradient(0deg, #080808 20%, #00000000 100%);
  112. }
  113. div#preview-img img{
  114.     width: 100%;
  115.     height: 100%;
  116.     object-fit: scale-down;
  117.     object-position: center center;
  118. }
  119. button.preview-close {
  120.     position: absolute;
  121.     top: 10px;
  122.     right: 15px;
  123.     height: 30px;
  124.     width: 30px;
  125.     background: #0000002e;
  126.     border: none;
  127.     box-shadow: 1px 1px 15px #ffffff36;
  128.     border-radius: 50%;
  129.     color: #cdcdcd;
  130.     font-size: 1.2rem;
  131.     font-weight: 500;
  132.     transition: all .2s ease;
  133.     cursor: pointer;
  134. }
  135. button.preview-close:hover{
  136.     transform: scale(1.02);
  137.     background: #00000093;
  138.     box-shadow: 1px 1px 15px #ffffff65;
  139. }
  140. @media (max-width: 700px){
  141.     div#preview-body{
  142.     width: 100%;
  143.     }
  144. }
  145. @media (max-height: 600px){
  146.     div#preview-body{
  147.     height: 100%;
  148.     }
  149. }
  150. button.previous-btn {
  151.     position: absolute;
  152.     top: calc(50% - 30px);
  153.     left: 10px;
  154.     font-size: 2rem;
  155.     padding: 10px 20px;
  156.     background: transparent;
  157.     color: #a39a9a;
  158.     font-weight: 500;
  159.     border: unset;
  160.     cursor: pointer;
  161. }
  162. button.previous-btn:hover{
  163.     background: #0000004d;
  164.     color: #e9e4e4;
  165. }
  166. button.next-btn {
  167.     position: absolute;
  168.     top: calc(50% - 30px);
  169.     right: 10px;
  170.     font-size: 2rem;
  171.     padding: 10px 20px;
  172.     background: transparent;
  173.     color: #a39a9a;
  174.     font-weight: 500;
  175.     border: unset;
  176.     cursor: pointer;
  177. }
  178. button.next-btn:hover{
  179.     background: #0000004d;
  180.     color: #e9e4e4;
  181. }

JavaScript

Finally, here is the JavaScript file script known as script.js. It contains the scripts that identify the images if it is either a portrait or landscape to add some attribute to the image parent elements for how the image should be shown on the page. It also contains the script for showing the image in the preview modal and navigating the image.

  1. const galleryWrapper = document.getElementById('gallery-wrapper')
  2. const imgItems = galleryWrapper.querySelectorAll('.gallery-item')
  3. const previewModal = document.getElementById('preview')
  4. const nextPreview = document.querySelector('.next-btn')
  5. const prevPreview = document.querySelector('.previous-btn')
  6.  
  7. const showPreviewModal = () => {
  8.     var img = galleryWrapper.querySelector('.gallery-item[data-is-Preview="true"] img').src
  9.     previewModal.querySelector('#preview-img img').src = img
  10.     if(!previewModal.classList.contains('show'))
  11.         previewModal.classList.add('show');
  12.     document.querySelector
  13. }
  14.  
  15. const closePreviewModal = () => {
  16.     if(galleryWrapper.querySelector('.gallery-item[data-is-Preview="true"]') != null){
  17.         galleryWrapper.querySelector('.gallery-item[data-is-Preview="true"]').dataset.isPreview = 'false'
  18.     }
  19.     if(previewModal.classList.contains('show'))
  20.         previewModal.classList.remove('show');
  21. }
  22. const nextItem = () => {
  23.     var currentItem = galleryWrapper.querySelector('.gallery-item[data-is-Preview="true"]')
  24.     if(currentItem.nextElementSibling != undefined)
  25.         var nextItem = currentItem.nextElementSibling;
  26.     else
  27.         var nextItem = galleryWrapper.querySelectorAll('.gallery-item')[0]
  28.  
  29.         console.log(currentItem, nextItem)
  30.     currentItem.dataset.isPreview = `false`
  31.     nextItem.dataset.isPreview = `true`
  32.     var img = galleryWrapper.querySelector('.gallery-item[data-is-Preview="true"] img').src
  33.     previewModal.querySelector('#preview-img img').src = img
  34. }
  35. const prevItem = () => {
  36.     var currentItem = galleryWrapper.querySelector('.gallery-item[data-is-Preview="true"]')
  37.     if(currentItem.previousElementSibling != undefined)
  38.         var prevItem = currentItem.previousElementSibling;
  39.     else
  40.         var prevItem = galleryWrapper.querySelectorAll('.gallery-item')[galleryWrapper.querySelectorAll('.gallery-item').length - 1]
  41.  
  42.         console.log(currentItem, prevItem)
  43.     currentItem.dataset.isPreview = `false`
  44.     prevItem.dataset.isPreview = `true`
  45.     var img = galleryWrapper.querySelector('.gallery-item[data-is-Preview="true"] img').src
  46.     previewModal.querySelector('#preview-img img').src = img
  47. }
  48. previewModal.querySelector('.preview-close').addEventListener('click', e=>{
  49.     e.preventDefault()
  50.     closePreviewModal()
  51. })
  52. nextPreview.addEventListener('click', e => {
  53.     e.preventDefault()
  54.     nextItem()
  55. })
  56. prevPreview.addEventListener('click', e => {
  57.     e.preventDefault()
  58.     prevItem()
  59. })
  60.  
  61. imgItems.forEach(el=>{
  62.     var img = el.querySelector('img')
  63.     var tmpImg = document.createElement('img')
  64.     tmpImg.src = img.src
  65.     var height = tmpImg.naturalHeight
  66.     var width = tmpImg.naturalWidth
  67.     if(height > width){
  68.         el.dataset.display = `portrait`
  69.     }else if(width > height){
  70.         el.dataset.display = `landscape`
  71.     }else{
  72.         el.dataset.display = `landscape`
  73.     }
  74.     el.addEventListener('click' , e=> {
  75.         e.preventDefault()
  76.         el.dataset.isPreview = 'true'
  77.         showPreviewModal()
  78.     })
  79. })
  80. galleryWrapper.style.display = `grid`
  81.    

Snapshots

Here are some snapshots of the overall result of the provided scripts.

Page UI

Creating an Image Gallery Grid View with Preview Modal using HTML, CSS, and JS

Desktop or Larger Screens Gallery Grid Display

Creating an Image Gallery Grid View with Preview Modal using HTML, CSS, and JS

Desktop or Larger Screens Preview Modal

Creating an Image Gallery Grid View with Preview Modal using HTML, CSS, and JS

Mobile or Smaller Screens Gallery Grid Display

Creating an Image Gallery Grid View with Preview Modal using HTML, CSS, and JS

Mobile or Smaller Screens Preview Modal

Creating an Image Gallery Grid View with Preview Modal using HTML, CSS, and JS

There you go! I have also provided the complete source code zip file on this website and it is free to download. The download button can be found below this tutorial's content. Feel free to download and modify the source code to do some enhancement and enhance your programming capabilities.

That's it! I hope this Creating an Image Gallery Grid View with Preview Modal using HTML, CSS, and JS Tutorial will help you with what you are looking for and that you'll find it useful for your current and future web application projects.

Explore more on this website for more Tutorials and Free Source Codes.

Happy Coding =)

Add new comment