Step 1: Setting Up the Project
First, create a project folder and add the following files:
📂 image-search-engine/
├── 📄 index.html (Main HTML file)
├── 🎨 style.css (Stylesheet)
├── ⚡ script.js (JavaScript functionality)
Step 2: Writing the HTML
Create an index.html
file and add the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Search Engine</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<div class="container">
<div class="hero">
<h1>Find the Perfect Image for Your Project</h1>
<p>Search millions of high-quality images powered by Unsplash. Just type a keyword and explore!</p>
<form>
<input type="text" placeholder="Search for images...">
<img src="search-icon.svg" alt="Search Icon">
</form>
<p class="discover">Discover stunning images for free. Start searching now!</p>
</div>
<div class="search-result">
<div id="loader" class="loader"></div>
</div>
<div class="show-more">
<button class="show-more-btn">Show More</button>
</div>
</div>
</main>
<footer>
<p>Powered by Unsplash API | Developed by Muhammad Kashif Pathan</p>
</footer>
<script src="script.js"></script>
</body>
</html>
📝 Explanation:
- The search bar allows users to enter a keyword.
- The search results are displayed inside
.search-result
. - A "Show More" button appears when there are more images to load.
- The footer credits the developer and Unsplash API.
🎨 Step 3: Styling with CSS
Create a style.css
file and add the following styles:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans
Unicode', Geneva, Verdana, sans-serif;
}
body {
color: white;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: rgb(9, 9, 9);
}
main {
width: 100%;
height: calc(100vh - 52px);
overflow: hidden auto;
text-align: center;
background-image: linear-gradient(rgba(0, 0, 0, 0.986), rgba(0, 0, 0, 0.936)),
url("bg-img.jpeg");
background-size: cover;
}
main::-webkit-scrollbar {
width: 0;
}
.container .hero {
background-image: linear-gradient(rgba(0, 0, 0, 0.968), rgba(0, 0, 0, 0.635)),
url("coding.jpg");
background-size: cover;
padding: 20px;
background-position: center;
background-size: cover;
}
.hero h1 {
margin-bottom: 20px;
background-color: rgba(10, 198, 60, 0.1);
border: 2px solid rgb(10, 198, 60);
border-radius: 50px;
padding: 10px 20px;
font-size: 16px;
display: inline-flex;
}
.hero p:nth-child(2) {
margin: 20px auto;
}
.hero form {
display: flex;
border-radius: 5px;
width: 100%;
justify-content: center;
}
.hero form input {
border: none;
outline: none;
border-radius: 10px 15px 15px 10px;
padding: 10px;
background-color: black;
color: white;
max-width: 500px;
width: 100%;
position: relative;
left: 20px;
font-size: 16px;
}
.hero form img {
padding: 10px;
cursor: pointer;
border-radius: 50%;
background-color: rgb(10, 198, 60);
border: 5px solid rgb(24, 24, 24);
position: relative;
left: -20px;
transition: all 0.8s linear;
}
.hero form img:hover {
border: 5px solid rgb(10, 198, 60);
}
.hero .discover {
margin: 20px auto;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90%;
}
.show-more button {
border: none;
padding: 10px 20px;
cursor: pointer;
border-radius: 0 5px 5px 0;
background-color: rgb(10, 198, 60);
color: white;
font-weight: 700;
transition: background-color 0.3s ease;
}
.hero form button:hover,
.show-more button:hover {
background-color: rgb(5, 158, 28);
}
.search-result {
width: 100%;
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
margin-top: 20px;
padding: 20px;
}
.search-result a {
width: calc(33.333% - 20px);
max-width: 300px;
background-color: transparent;
border-radius: 5px;
overflow: hidden;
transition: all 0.3s ease;
}
.search-result a img {
width: 100%;
height: 200px;
object-fit: cover;
object-position: center;
display: block;
}
.search-result a:hover {
transform: scale(1.05);
}
.hide {
display: none;
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #1e1e1e;
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
background: #555;
border-radius: 10px;
transition: all 0.3s ease;
}
::-webkit-scrollbar-thumb:hover {
background: #888;
}
::-webkit-scrollbar-thumb:active {
background: #aaa;
}
* {
scrollbar-width: thin;
scrollbar-color: #555 #1e1e1e;
}
.loader {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50px;
height: 50px;
border: 6px solid rgba(255, 255, 255, 0.3);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
z-index: 1000;
background-color: transparent;
display: none;
}
.loader {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50px;
height: 50px;
border: 6px solid rgba(255, 255, 255, 0.3);
border-top-color: #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
display: none;
}
@keyframes spin {
0% {
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
transform: translate(-50%, -50%) rotate(360deg);
}
}
.show-more {
display: flex;
justify-content: center;
}
.show-more-btn {
margin-top: 20px;
padding: 10px 20px;
border-radius: 5px;
font-size: 14px;
font-weight: 700;
display: none;
}
footer p {
font-size: 10px;
color: gray;
font-weight: 700;
padding: 20px;
height: 52px;
}
@media (max-width: 768px) {
.search-result a {
width: calc(50% - 10px);
}
}
@media (max-width: 550px) {
main {
padding: 20px 0;
}
.container .hero {
padding: 20px 10px;
}
.hero, .hero h1 {
font-size: 12px;
}
.search-result {
padding: 10px;
}
.search-result a {
min-width: 100%;
}
.search-result a img {
height: 250px;
}
}
📝 Explanation:
- A dark theme with a stylish look.
- The search input is centered and responsive.
- The images appear in a grid format with hover effects.
- The "Show More" button is hidden by default until results are loaded.
Your web page will look like this.
⚡ Step 4: JavaScript for Functionality
Create a script.js
file and add the following code:
const accessKey = "YOUR_UNSPLASH_API_KEY";
const form = document.querySelector("form");
const searchInp = document.querySelector("input");
const searchResult = document.querySelector(".search-result");
const showMoreBtn = document.querySelector(".show-more-btn");
const loader = document.getElementById("loader");
const discoverText = document.querySelector(".discover");
let keyword = "";
let page = 1;
async function searchImages() {
keyword = searchInp.value.trim();
if (!keyword) return;
if (page === 1) {
searchResult.innerHTML = "";
discoverText.textContent = "";
discoverText.style.display = "block";
}
loader.style.display = "block";
const url = `https://api.unsplash.com/search/photos?page=${page}&query=${keyword}&client_id=${accessKey}&per_page=12`;
try {
const response = await fetch(url);
if (!response.ok) throw new Error("Failed to fetch images");
const data = await response.json();
const results = data.results;
if (results.length === 0) {
discoverText.textContent = `No images found for "${keyword}". Try a different keyword.`;
showMoreBtn.style.display = "none";
loader.style.display = "none";
return;
}
// Append new images
results.forEach((result) => {
const image = document.createElement("img");
image.src = result.urls.small;
image.alt = result.alt_description || "Search result image";
const imageLink = document.createElement("a");
imageLink.href = result.links.html;
imageLink.target = "_blank";
imageLink.appendChild(image);
searchResult.appendChild(imageLink);
});
discoverText.style.display = "none";
showMoreBtn.style.display = results.length > 0 ? "block" : "none";
} catch (error) {
console.error("Error fetching images:", error);
searchResult.innerHTML = `<p class="error-message">Something went wrong. Please try again later.</p>`;
} finally {
// Hide loader after fetching is complete
setTimeout(() => {
loader.style.display = "none";
}, 500);
}
}
form.addEventListener("submit", (e) => {
e.preventDefault();
page = 1;
searchImages();
});
showMoreBtn.addEventListener("click", () => {
page++;
searchImages();
});
📝 Explanation:
- Fetches images from Unsplash API.
- Displays results dynamically on the webpage.
- Shows a "Show More" button for additional images.
🎉 Conclusion
Congratulations! 🎉 You’ve successfully built your own Image Search Engine! This is a great beginner-friendly project that teaches API integration, dynamic content rendering, and responsive design.
🔗 Try the live demo: GitHub Link
👉 What will you build next? Let me know in the comments! 🚀
Comments
Post a Comment