Hello guys, In today's article you'll learn to create this unsplash clone. If you don't know what unsplash is, unsplash is a website/company which offers royalty free images for personal or business use. We'll today create this website using unsplash API. It's a great javascript project for beginner.
So, without wasting more time, let's start. To see project demo or you want a video tutorial. You can watch the tutorial below.
Video Tutorial
I appreciate if you can support me by subscribing my youtube channel.
Code
So, let's start with our folder structure. You can see the files we'll use, below.
So, let's make our home page first.
Home Page
Header Section
In our home page, we have a beautiful header section. To create that. Open index.html
file. Inside that, code these elements.
<header class="header-section">
<div class="header-content">
<h1 class="logo">logo</h1>
<p class="sub-line">the best royalty free images you can find here.</p>
<form action="search.html">
<input type="text" autocomplete="off" name="search" class="search-box" placeholder="search image">
<button class="search-btn" type="submit">search</button>
</form>
</div>
</header>
Without CSS HTML is nothing, is't it. So, let's style our header element.
*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'roboto', sans-serif;
}
.header-section{
width: 100%;
height: 100vh;
position: relative;
background-image: url('../img/bg.png');
background-size: cover;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.logo{
font-size: 80px;
font-weight: 400;
color: #fff;
text-transform: capitalize;
}
.sub-line{
color: #fff;
padding: 20px 0 30px;
font-size: 20px;
text-transform: capitalize;
word-spacing: 2px;
position: relative;
font-weight: 300;
}
.sub-line::after{
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60%;
height: 1px;
background: #fff;
}
.sub-line::before{
content: '';
position: absolute;
bottom: -5px;
left: 50%;
transform: translateX(-50%);
width: 10px;
height: 10px;
background: #fff;
border-radius: 50%;
}
.search-box{
display: block;
margin: 60px auto 20px;
width: 100%;
height: 40px;
border-radius: 5px;
padding: 10px;
border: none;
outline: none;
text-transform: capitalize;
}
.search-btn{
padding: 10px 30px;
border-radius: 5px;
text-transform: capitalize;
border: none;
outline: none;
cursor: pointer;
background: #0a1113;
color: #fff;
}
Those are lots of styling. After giving these CSS, we are done with our header section.
Output
Isn't it looking great.
Gallery Section
After header section, we have image recommendations or image gallery in our home page in mansory layout. To create mansory layout, first we need some elements or images.
After header section in index.html
<section class="gallery">
<img src="img/img (1).png" class="gallery-img" alt="">
<img src="img/img (1).png" class="gallery-img" alt="">
<img src="img/img (1).png" class="gallery-img" alt="">
<img src="img/img (1).png" class="gallery-img" alt="">
<img src="img/img (1).png" class="gallery-img" alt="">
<img src="img/img (1).png" class="gallery-img" alt="">
<img src="img/img (1).png" class="gallery-img" alt="">
<img src="img/img (1).png" class="gallery-img" alt="">
</section>
For now create 8 image elements. And give them some styles.
/* gallery */
.gallery{
width: 100%;
padding: 40px;
background: #fff;
columns: 4;
column-gap: 20px;
}
.gallery-img{
width: 100%;
height: 100%;
object-fit: cover;
margin-bottom: 20px;
border-radius: 5px;
cursor: pointer;
background: #f9f9f9;
}
Output
If you create less than 8 images, you'll probably don't see images in 4 columns. This is because, we have used columns
CSS property to create grid. Note - we are not using grid here, cause grid create a fixed size row and columns and we want images to have their proportions. Columns
property is used to define columns for elements in CSS without using grid. This don't restrict you with fixed row height.
So, now you can remove the hard coded image elements from index.html
. and let's make it with JS. So open app.js
.
In app.js
file, first you need to store your unsplash API key. If you don't know how to create one, then check this.
const access_key = 'your api key';
Once you got your key, we need random photo url, so that we can get random photos, you can find the url in the unsplash documentation. but for your ease, here it is.
const random_photo_url = `https://api.unsplash.com/photos/random?client_id=${access_key}&count=30`;
Here access_key
is your api key. And I am using JS template literals here.
Now, make a function getImages
. This function will make request to random photo URL.
let allImages; // this will store all the images
const getImages = () => {
fetch(random_photo_url)
.then(res => res.json())
.then(data => {
allImages = data;
makeImages(allImages);
});
}
allImages
will store the fetched data, so we can access the data after receiving it outside the function. So, now once we got the images, we need to make dynamic image elements, for that make makeImages
function.
const gallery = document.querySelector('.gallery');
const makeImages = (data) => {
data.forEach((item, index) => {
let img = document.createElement('img');
img.src = item.urls.regular;
img.className = 'gallery-img';
gallery.appendChild(img);
})
}
So, after this you should see random images being fetched from API and created with JS dynamically.
getImages()
Make sure to call the function
Output
Great! now, let's create image popup effect. For that again open your index.html
file.
Image popup
Create image popup before gallery
. Or you can it after also it doesn't really matters π
<!-- popup window -->
<div class="image-popup">
<button class="close-btn"></button>
<a href="#" class="download-btn">download image</a>
<img src="img/img (1).png" class="large-img" alt="">
<button class="controls pre-btn"><img src="img/pre.png" alt=""></button>
<button class="controls nxt-btn"><img src="img/nxt.png" alt=""></button>
</div>
/* image popup */
.image-popup{
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80%;
height: 80vh;
background: #f9f9f9;
box-shadow: 0px 5px 50px rgba(0, 0, 0, 0.25);
border-radius: 10px;
transition: .5s;
display: flex;
justify-content: center;
align-items: center;
}
.image-popup.hide{
display: none;
opacity: 0;
}
.close-btn{
position: absolute;
top: 10px;
left: 10px;
width: 20px;
height: 20px;
background: #ff4f4f;
border-radius: 50%;
border: none;
cursor: pointer;
}
.download-btn{
text-transform: capitalize;
padding: 10px 20px;
background: #192f2e;
color: #fff;
text-decoration: none;
border-radius: 5px;
position: absolute;
right: 10px;
top: 10px;
}
.large-img{
height: 80%;
width: auto;
max-width: 80%;
object-fit: cover;
border-radius: 10px;
}
.controls{
background: none;
border: none;
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
}
.pre-btn{
left: 20px;
}
.nxt-btn{
right: 20px;
}
Output
You can see in above styles, we have hide
class which is setting display
to none
. So add hide
class to image-popup
element. You can also remove the image source from large-img
Now, let's make it functional with Javascript.
let currentImage = 0; // will track the current large image
const makeImages = (data) => {
data.forEach((item, index) => {
..previous code..
// popup image
img.addEventListener('click', () => {
currentImage = index;
showPopup(item);
})
})
}
This above code will add click event to all the images, so that we can open the popup. So, now let's create showPopup
function.
const showPopup = (item) => {
let popup = document.querySelector('.image-popup');
const downloadBtn = document.querySelector('.download-btn');
const closeBtn = document.querySelector('.close-btn');
const image = document.querySelector('.large-img');
popup.classList.remove('hide');
downloadBtn.href = item.links.html;
image.src = item.urls.regular;
closeBtn.addEventListener('click', () => {
popup.classList.add('hide');
})
}
In this function, first we are selecting all the HTML elements using querySelector
method. And then removing hide
class from popup element. also setting up download image btn link along with image source. And yes, we are also add close functionality.
So, we just have to make controls now.
// controls
const preBtns = document.querySelector('.pre-btn');
const nxtBtns = document.querySelector('.nxt-btn');
preBtns.addEventListener('click', () => {
if(currentImage > 0){
currentImage--;
showPopup(allImages[currentImage]);
}
})
nxtBtns.addEventListener('click', () => {
if(currentImage < allImages.length - 1){
currentImage++;
showPopup(allImages[currentImage]);
}
})
Above code is also very simple. In above code, we are selecting the previous and next buttons and adding click event to them. Inside the events, I am checking for condition to validate end image.
So great. We are done with our home page. Let's create our search page now.
Search Page
Our search page is very simple. To start, copy all the elements from index.html
except header section. and paste it inside this file. After done with that, make a search box at the very start of body tag.
<form action="search.html" class="search-container">
<input type="text" autocomplete="off" name="search" class="search-input" placeholder="search image">
<button class="search" type="submit">search</button>
</form>
Make sure you link search.css
& app.js
file to it. Now, add these form styles to search.css
.
.search-container{
width: 100%;
height: 60px;
background: #0a1113;
padding: 10px 40px;
display: flex;
justify-content: space-between;
}
.search-input{
width: 95%;
height: 40px;
border-radius: 5px;
border: none;
outline: none;
padding: 20px;
text-transform: capitalize;
}
.search{
background: none;
border: none;
color: #fff;
text-transform: capitalize;
cursor: pointer;
}
After all of this, you should see something like this.
Output
Now, let's fetch images related to search keyword. Inside app.js
let searchParam = location.search.split('=').pop(); // this will give extract the search keyword from URL
const search_photo_url = `https://api.unsplash.com/search/photos?client_id=${access_key}&query=${searchParam}&per_page=50`; // this is search image URL
Now, create a function to make request to the URL.
const searchImages = () => {
fetch(search_photo_url)
.then(res => res.json())
.then(data => {
allImages = data.results;
makeImages(allImages);
});
}
After this, we just need to check we are on home page or search page and call the function according to it. So instead of calling simple getImages();
wrap that to this condition along with this code.
if(searchParam == ''){
getImages();
} else{
searchImages();
}
So above condition is simple when we open home page, our searchParam
will be an empty string. That's why I am comparing that to check for the page.
Output
I searched for cars
So, that's it. Great work guys. We are done with the project. So, how is this project, and did you learn something new from this.
I hope you understood each and everything. If you have doubt or I missed something let me know in the comments.
Articles you may find Useful
I really appreciate if you can subscribe my youtube channel. I create awesome web contents.
Source Code
Thanks for reading
Top comments (3)
Cool project ! Don't hesitate to check ππΌπΈ
#unsplash
Amazing and awesome post this is .
Good going
Keep it up.
Helpful thanks for sharing