Hey guys, In this tutorial, we'll walk through the process of creating a responsive image expand gallery using HTML, CSS, and JavaScript. This gallery allows users to click on thumbnail images, triggering an expansion effect to showcase the selected image in greater detail. We'll cover the HTML structure, CSS styling, and JavaScript functionality, providing a comprehensive guide for both beginners and those looking to enhance their web development skills. Letโs dive right in ๐
๐งฐ Prerequisites
To follow along with this tutorial, you should have a basic understanding of HTML, CSS, and JavaScript(Iโll still explain everything in depth though). You should also have a code editor installed on your computer, such as Visual Studio Code or any other text editor that you use.
๐๏ธ HTML CODE ๐๐ฝ
Letโs start creating an image container (div
with the class "image-container") and individual image div
with the class image
within it. The image
class will also have two elements which is the individual img
element and a span
element with some text and emojis
<div class="image-container">
<div class="image active">
<img
src="https://images.unsplash.com/photo-1472214103451-9374bd1c798e?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="nature"
title="nature"
/>
<span> Nature โ </span>
</div>
<div class="image">
<img
src="https://images.unsplash.com/photo-1511593358241-7eea1f3c84e5?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="water"
title="water"
/>
<span>Ocean ๐ฆ</span>
</div>
<div class="image">
<img
src="https://images.unsplash.com/photo-1531884070720-875c7622d4c6?q=80&w=2071&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="eagle"
title="eagle"
/>
<span>Eagle ๐ฆ
</span>
</div>
<div class="image">
<img
src="https://images.unsplash.com/photo-1504754524776-8f4f37790ca0?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="food"
title="food"
/>
<span>Food ๐ฅ</span>
</div>
<div class="image">
<img
src="https://images.unsplash.com/photo-1553440569-bcc63803a83d?q=80&w=2025&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="car"
title="car"
/>
<span>Car ๐</span>
</div>
</div>
The active
class you are seeing is what we are going to use to track the current image
we are on so that it can be expanded. But weโll see it in action in a bit.
Here is the HTML code in full ๐๐ฝ
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Image expand gallery</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="image-container">
<div class="image active">
<img
src="https://images.unsplash.com/photo-1472214103451-9374bd1c798e?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="nature"
title="nature"
/>
<span> Nature โ </span>
</div>
<div class="image">
<img
src="https://images.unsplash.com/photo-1511593358241-7eea1f3c84e5?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="water"
title="water"
/>
<span>Ocean ๐ฆ</span>
</div>
<div class="image">
<img
src="https://images.unsplash.com/photo-1531884070720-875c7622d4c6?q=80&w=2071&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="eagle"
title="eagle"
/>
<span>Eagle ๐ฆ
</span>
</div>
<div class="image">
<img
src="https://images.unsplash.com/photo-1504754524776-8f4f37790ca0?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="food"
title="food"
/>
<span>Food ๐ฅ</span>
</div>
<div class="image">
<img
src="https://images.unsplash.com/photo-1553440569-bcc63803a83d?q=80&w=2025&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="car"
title="car"
/>
<span>Car ๐</span>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
Here is the output so far ๐๐ฝ
You can see that the images are just all over the place. so letโs add some styling to it.
๐ก CSS CODE
The CSS style looks a bit lengthy, But we are going to break it down into different parts for easier understanding.
First, we are going to add a CSS reset, ensuring consistent box model behavior by zeroing out margins and padding for all elements.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
After that, we are now going to style all img
elements, setting their maximum width to 100%, adding a border-radius of 1rem (rounded corners), and setting a pointer cursor. ๐๐ฝ
img {
max-width: 100%;
border-radius: 1rem;
cursor: pointer;
}
Now were are going to style the body
element by centering the content both horizontally and vertically using grid
, set the body's height to 100vh
and width to 100% of the viewport, hide overflow, and sets a background color. ๐๐ฝ
body {
display: grid;
place-items: center;
height: 100vh;
width: 100%;
overflow: hidden;
background-color: #464343;
}
Next, weโll be styling the image-container (div
with class .image-container
). Weโll use Flexbox to display its children in a row with a 1rem gap. We are also going to set a maximum width of 900px, a width of 100% minus 100px, centering it in the middle using auto margin, and padding. Weโll also set the overflow
to hidden. ๐๐ฝ
.image-container {
display: flex;
gap: 1rem;
max-width: 900px;
width: calc(100% - 100px);
margin-inline: auto;
padding: 0 1rem;
overflow: hidden;
}
Next, weโll be styling the image
class that is within the image-container
. Weโll give it a position of relative
because weโll be setting the position of the span
element to absolute
, give it a fixed width and height, add some rounded corners, and a transition effect using cubic-bezier timing function. ๐๐ฝ
.image-container .image {
position: relative;
width: 60px;
height: 400px;
border-radius: 1rem;
overflow: hidden;
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95);
}
Next, weโll be styling the img
elements within the image
container. Weโll give it a width and height of 100% to inherit the width and height of the parent container which is the image
container, weโll also use object-fit: cover
to maintain aspect ratio while covering the entire container, and have a transition effect. ๐๐ฝ
.image-container .image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95);
}
Next, weโll be styling the span
element. weโll first of all set to inline-block, positioned absolute with a background color, padding, rounded corners, text color, font size, and initial scale set to 0. weโll also give it a transition effect with a delay so that the image will expand fully before the text will pop up. ๐๐ฝ
span {
display: inline-block;
position: absolute;
left: 1rem;
bottom: 1rem;
background-color: #000;
padding: 0.7rem 1rem;
border-radius: 100vw;
color: #fff;
font-size: 1.2rem;
transform: scale(0);
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95) 0.3s;
}
Next will be the style for the active state of the image container. When an image is active, it takes up 100% width, and the span inside it scales to 1. ๐๐ฝ
.image-container .active {
width: 100%;
}
.image-container .active span {
transform: scale(1);
}
Lastly for the CSS, weโll be adding media query for smaller screens and below so that the images can stack from top to bottom(horizontally) instead of vertically which is the default. So, weโll change the flex direction, adjusts the max-width and height of the image container, modify the height of images and active state accordingly. ๐๐ฝ
@media (max-width: 576px) {
/* Styles for screens with a maximum width of 576px */
.image-container {
flex-direction: column;
max-width: 2000px;
width: 100%;
height: 400px;
}
.image-container .image {
width: 100%;
height: 60px;
transition: height 0.5s ease-in-out;
}
.image-container .active {
height: 400px;
}
}
Here is the CSS code in full ๐๐ฝ
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
img {
max-width: 100%;
border-radius: 1rem;
cursor: pointer;
}
body {
font-family: 'Poppins', sans-serif;
display: grid;
place-items: center;
height: 100vh;
width: 100%;
overflow: hidden;
background-color: #464343;
}
.image-container {
display: flex;
gap: 1rem;
max-width: 900px;
width: calc(100% - 100px);
margin-inline: auto;
padding: 0 1rem;
overflow: hidden;
}
.image-container .image {
position: relative;
width: 60px;
height: 400px;
border-radius: 1rem;
overflow: hidden;
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95);
}
.image-container .image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95);
}
span {
display: inline-block;
position: absolute;
left: 1rem;
bottom: 1rem;
background-color: #000;
padding: 0.7rem 1rem;
border-radius: 100vw;
color: #fff;
font-size: 1.2rem;
transform: scale(0);
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95) 0.3s;
}
.image-container .active {
width: 100%;
}
.image-container .active span {
transform: scale(1);
}
@media (max-width: 576px) {
.image-container {
flex-direction: column;
max-width: 2000px;
width: 100%;
height: 400px;
}
.image-container .image {
width: 100%;
height: 60px;
transition: height 0.5s ease-in-out;
}
.image-container .image img {
width: 100%;
height: 100%;
}
.image-container .active {
height: 400px;
}
}
Here is the output of HTML and CSS code so far ๐๐ฝ
๐๏ธ JAVASCRIPT CODE
The JavaScript code will be very minimal because the main work is in the CSS which weโve already tackled. Itโs basically just 14 lines of code. So letโs break it down ๐๐ฝ
Weโll first of all select all elements with the class 'image' using document.querySelectorAll
and store it in a variable called images
, thereby creating a NodeList of all matching elements. ๐๐ฝ
const images = document.querySelectorAll('.image');
Next, weโll create a function called expandImage
which will be responsible for handling the expansion logic. and weโll iterate through each element in the images
NodeList using forEach
. For each image and also add a click event listener.
const expandImage = () => {
images.forEach((image) => {
image.addEventListener('click', () => {
const active = document.querySelector('.active');
active.classList.remove('active');
image.classList.add('active');
});
});
};
Upon clicking an image, the function does the following:
- Finds the currently active image using
document.querySelector('.active')
and stores it in the variableactive
. - Removes the 'active' class from the currently active image using
active.classList.remove('active')
. - Adds the 'active' class to the clicked image using
image.classList.add('active')
, making it the new active image.
And lastly, we are just going to invoke the function ๐๐ฝ
expandImage();
Here is the JavaScript code in full ๐๐ฝ
const images = document.querySelectorAll('.image');
const expandImage = () => {
images.forEach((image) => {
image.addEventListener('click', () => {
const active = document.querySelector('.active');
active.classList.remove('active');
image.classList.add('active');
});
});
};
expandImage();
CONCLUSION
Thatโs it guys. Hope you learned something from this article. You can get the code or see it in action from my Codepen and feel free to play around with the code and even come up with something better. Till next time ๐
Top comments (0)