Cách Tạo Website Ảnh Miễn Phí Với API Pexels Bằng HTML, CSS, JavaScript

Bạn muốn tạo một website ảnh miễn phí như Unsplash hoặc Pexels nhưng không biết bắt đầu từ đâu? Bài viết này sẽ hướng dẫn bạn cách sử dụng API của Pexels để xây dựng một website gallery ảnh miễn phí với HTML, CSS, và JavaScript.
API Pexels Bằng HTML, CSS, JavaScript

Cách làm nhanh:

  1. Đăng ký tài khoản Pexels → Lấy API Key miễn phí
  2. Chuẩn bị code HTML, CSS, JavaScript (có sẵn template gallery)
  3. Chèn API Key vào code để gọi dữ liệu ảnh
  4. Chạy code → Website sẽ hiển thị ảnh miễn phí, có chức năng tìm kiếm, load more và tải ảnh

Hướng dẫn chi tiết:

  1. HTML: Tạo khung giao diện gồm thanh tìm kiếm, gallery hiển thị ảnh, nút tải thêm
  2. CSS: Thiết kế responsive, lưới ảnh đẹp, hiệu ứng hover chuyên nghiệp
  3. JavaScript:
  • Gọi API từ Pexels bằng fetch()
  • Hiển thị danh sách ảnh + tên tác giả
  • Tích hợp nút Load More để tải thêm ảnh
  • Tạo Lightbox để xem ảnh chi tiết + nút download
👉 Khi chạy xong, bạn đã có một website ảnh miễn phí cực đẹp, dễ dùng và có thể mở rộng thêm nhiều tính năng nâng cao.

Dưới đây là code cho ban sử dụng.

<!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>
    <style>
      /* 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:0}.gallery .load-more{padding:10px 25px;font-size:1.05rem}}

    </style>
  </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="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6E_ZO9QpRVOz5_Vli7Y9upKWnRHXsvTffl6i0JvEP0-4Khnx7anHOIpLNZ5onMTVZ9cFjqJHASx4reXIZjDM51QTIFucizF21E2h-i5YFc-BCo54xTRB-Zf1VrNbuw__C2j6GximnwnMGH085kTKacdURt14R1g5kcGG4FSmoQiOQuMpxDgrBLJzdP0Y/s1600/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>
    <script>
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 = "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));

    </script>
  </body>
</html>
Video hướng dẫn tại đây >>
Xem thêm: Phần 2: Tools Chuyển Đổi Ảnh Hàng Loạt Sang WebP
No Copyright © A Vèo
Trên đây là bài viết Cách Tạo Website Ảnh Miễn Phí Với API Pexels Bằng HTML, CSS, JavaScript Nếu bạn cảm thấy bài viết chưa đầy đủ hoặc không được như bạn mong đợi thì hãy để lời góp ý của bạn dưới phần comments nhé!
VeoSpot.net có sinh nhật vào 9 tháng 3

Đăng nhận xét

Post template