Chào mừng các bạn đến với Rcom Dăm Yi blog - Kho tài liệu bổ ích!, Chúng tôi sẽ từng bước hoàn thiện để bạn đọc cảm thấy hài lòng, hữu ích!

Thứ Sáu, 23 tháng 1, 2026

Bài 15: Mini Project – Landing Page 1 trang (HTML + CSS + JS)

🎯 Mục tiêu

  • Vận dụng HTML semantic + CSS (Flex/Grid) để dựng landing page
  • Biết tạo menu cuộn đến section (anchor link)
  • Biết làm nút “Lên đầu trang” bằng JavaScript
  • Biết tạo hiệu ứng scroll mượt
  • (Nâng cao) Hiển thị trạng thái menu đang chọn

📘 Mô tả sản phẩm

Bạn sẽ làm một Landing Page gồm các phần:

  • Header + Menu
  • Hero (giới thiệu) + nút CTA
  • Features (3–6 tính năng)
  • Gallery (lưới ảnh giả lập)
  • Contact (form)
  • Footer

💻 Code mẫu (Landing Page hoàn chỉnh)


<!doctype html>
<html lang="vi">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Bài 15 - Landing Page</title>

  <style>
    *{ box-sizing:border-box; }
    html{ scroll-behavior: smooth; }

    body{
      margin:0;
      font-family: Arial;
      background:#f7f8fa;
      line-height: 1.7;
      color:#111;
    }

    /* ===== HEADER ===== */
    header{
      position: sticky;
      top:0;
      z-index: 10;
      background:#111;
      color:#fff;
      border-bottom: 1px solid rgba(255,255,255,0.1);
    }
    .nav{
      max-width: 1100px;
      margin: 0 auto;
      padding: 12px 16px;
      display:flex;
      align-items:center;
      justify-content: space-between;
      gap: 12px;
    }
    .brand{
      font-weight: 800;
      letter-spacing: 0.4px;
    }
    .menu{
      display:flex;
      gap: 12px;
      flex-wrap:wrap;
      justify-content: flex-end;
    }
    .menu a{
      color:#fff;
      text-decoration:none;
      font-weight: 700;
      padding: 6px 10px;
      border-radius: 10px;
      opacity: .9;
    }
    .menu a:hover{ background: rgba(255,255,255,0.12); opacity:1; }
    .menu a.active{ background:#2563eb; opacity:1; }

    /* ===== SECTIONS ===== */
    .wrap{
      max-width: 1100px;
      margin: 0 auto;
      padding: 18px 16px 40px;
    }
    section{
      background:#fff;
      border:1px solid #e5e5e5;
      border-radius: 16px;
      padding: 18px;
      margin-top: 16px;
    }

    /* ===== HERO ===== */
    .hero{
      display:grid;
      grid-template-columns: 1.2fr 0.8fr;
      gap: 16px;
      align-items:center;
      overflow:hidden;
    }
    .hero h1{ margin:0 0 8px; font-size: 30px; }
    .hero p{ margin:0; color:#333; }
    .cta{
      display:flex;
      gap: 10px;
      margin-top: 12px;
      flex-wrap:wrap;
    }
    .btn{
      display:inline-block;
      padding: 10px 14px;
      border-radius: 12px;
      border:0;
      cursor:pointer;
      font-weight: 800;
      text-decoration:none;
      text-align:center;
    }
    .btn.primary{ background:#2563eb; color:#fff; }
    .btn.dark{ background:#111; color:#fff; }

    .hero-card{
      border:1px solid #e5e5e5;
      border-radius: 16px;
      padding: 14px;
      background: #f3f4f6;
    }
    .kpi{
      display:grid;
      grid-template-columns: 1fr 1fr;
      gap: 10px;
      margin-top: 10px;
    }
    .kpi .item{
      background:#fff;
      border:1px solid #e5e5e5;
      border-radius: 14px;
      padding: 12px;
      text-align:center;
    }
    .kpi b{ font-size: 18px; }

    /* ===== FEATURES ===== */
    .grid3{
      display:grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 14px;
    }
    .feature{
      border:1px solid #e5e5e5;
      border-radius: 16px;
      padding: 14px;
      background:#fff;
    }
    .feature h3{ margin:0 0 8px; }
    .feature p{ margin:0; color:#333; }

    /* ===== GALLERY ===== */
    .gallery{
      display:grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 12px;
    }
    .ph{
      height: 130px;
      border-radius: 16px;
      border:1px solid #e5e5e5;
      background:#e5e7eb;
      display:flex;
      align-items:center;
      justify-content:center;
      font-weight: 800;
    }

    /* ===== CONTACT ===== */
    .form{
      display:grid;
      grid-template-columns: 1fr 1fr;
      gap: 12px;
    }
    label{ font-weight: 700; display:block; margin-bottom: 6px; }
    input, textarea{
      width:100%;
      padding: 10px 12px;
      border:1px solid #ddd;
      border-radius: 12px;
      outline:none;
      font-size: 14px;
    }
    textarea{ grid-column: 1 / -1; resize: vertical; min-height: 120px; }
    .form .full{ grid-column: 1 / -1; }
    .msg{
      margin-top: 10px;
      padding: 10px 12px;
      border-radius: 12px;
      background:#f3f4f6;
      border:1px solid #e5e7eb;
      color:#111;
    }

    /* ===== FOOTER ===== */
    footer{
      text-align:center;
      padding: 18px 0 30px;
      color:#555;
      font-size: 14px;
    }

    /* ===== BACK TO TOP ===== */
    #toTop{
      position: fixed;
      right: 16px;
      bottom: 16px;
      display:none;
      padding: 10px 12px;
      border-radius: 999px;
      border:0;
      cursor:pointer;
      background:#111;
      color:#fff;
      font-weight: 800;
    }

    /* ===== RESPONSIVE ===== */
    @media (max-width: 900px){
      .hero{ grid-template-columns: 1fr; }
      .grid3{ grid-template-columns: 1fr; }
      .form{ grid-template-columns: 1fr; }
      .menu{ justify-content:center; }
    }
  </style>
</head>

<body>

  <header>
    <div class="nav">
      <div class="brand">Web Tĩnh Course</div>
      <nav class="menu" id="menu">
        <a href="#home" class="active">Home</a>
        <a href="#features">Features</a>
        <a href="#gallery">Gallery</a>
        <a href="#contact">Contact</a>
      </nav>
    </div>
  </header>

  <div class="wrap">

    <section id="home" class="hero">
      <div>
        <h1>Landing Page 1 trang – web tĩnh</h1>
        <p>
          Bạn đang xem một mẫu landing page dùng HTML + CSS + JavaScript.
          Nó phù hợp để nhúng Blogspot, làm giới thiệu khóa học, sản phẩm, dịch vụ.
        </p>

        <div class="cta">
          <a class="btn primary" href="#contact">Đăng ký ngay</a>
          <button class="btn dark" id="btnDemo">Xem thông báo</button>
        </div>

        <div class="msg" id="heroMsg">Sẵn sàng.</div>
      </div>

      <div class="hero-card">
        <b>Tóm tắt nhanh</b>
        <div class="kpi">
          <div class="item"><b>15</b><br>Bài học</div>
          <div class="item"><b>3</b><br>Mini Project</div>
          <div class="item"><b>HTML</b><br>Cấu trúc</div>
          <div class="item"><b>JS</b><br>Tương tác</div>
        </div>
      </div>
    </section>

    <section id="features">
      <h2>Features</h2>
      <div class="grid3">
        <div class="feature">
          <h3>1) Dễ học</h3>
          <p>Bố cục rõ ràng, code ngắn gọn, thực hành ngay.</p>
        </div>
        <div class="feature">
          <h3>2) Chuẩn Blogspot</h3>
          <p>Nhúng được vào bài viết/Trang mà không cần server.</p>
        </div>
        <div class="feature">
          <h3>3) Có tương tác</h3>
          <p>JavaScript xử lý nút bấm, form, và hiệu ứng.</p>
        </div>
      </div>
    </section>

    <section id="gallery">
      <h2>Gallery</h2>
      <p style="margin-top:0;color:#333">Mẫu lưới ảnh giả lập bằng CSS Grid.</p>
      <div class="gallery">
        <div class="ph">Ảnh 1</div>
        <div class="ph">Ảnh 2</div>
        <div class="ph">Ảnh 3</div>
        <div class="ph">Ảnh 4</div>
        <div class="ph">Ảnh 5</div>
        <div class="ph">Ảnh 6</div>
      </div>
    </section>

    <section id="contact">
      <h2>Contact</h2>
      <p style="margin-top:0;color:#333">Form demo (không gửi server), JS chỉ kiểm tra và hiển thị.</p>

      <form id="contactForm" class="form">
        <div>
          <label for="cname">Họ tên</label>
          <input id="cname" type="text" placeholder="Nhập họ tên..." required>
        </div>

        <div>
          <label for="cemail">Email</label>
          <input id="cemail" type="email" placeholder="vd: abc@gmail.com" required>
        </div>

        <div class="full">
          <label for="cmsg">Nội dung</label>
          <textarea id="cmsg" placeholder="Bạn muốn tư vấn gì?" required></textarea>
        </div>

        <div class="full">
          <button class="btn primary" type="submit">Gửi</button>
          <span class="msg" id="contactMsg">Chưa gửi.</span>
        </div>
      </form>
    </section>

    <footer>
      © 2026 • Landing Page Demo • HTML/CSS/JS
    </footer>

  </div>

  <button id="toTop" title="Lên đầu trang">↑</button>

  <script>
    // ===== 1) Nút demo thông báo =====
    const btnDemo = document.getElementById("btnDemo");
    const heroMsg = document.getElementById("heroMsg");
    btnDemo.addEventListener("click", () => {
      const t = new Date().toLocaleTimeString("vi-VN");
      heroMsg.textContent = "Bạn vừa bấm nút lúc: " + t;
    });

    // ===== 2) Form contact (demo) =====
    const form = document.getElementById("contactForm");
    const contactMsg = document.getElementById("contactMsg");
    form.addEventListener("submit", (e) => {
      e.preventDefault();
      const name = document.getElementById("cname").value.trim();
      const email = document.getElementById("cemail").value.trim();
      const message = document.getElementById("cmsg").value.trim();

      if(name.length < 2){
        contactMsg.textContent = "❌ Tên quá ngắn.";
        return;
      }
      if(message.length < 5){
        contactMsg.textContent = "❌ Nội dung quá ngắn.";
        return;
      }

      contactMsg.textContent = "✅ Đã nhận: " + name + " (" + email + ")";
      form.reset();
    });

    // ===== 3) Back to Top =====
    const toTop = document.getElementById("toTop");
    window.addEventListener("scroll", () => {
      if(window.scrollY > 400) toTop.style.display = "block";
      else toTop.style.display = "none";
      highlightMenu();
    });
    toTop.addEventListener("click", () => {
      window.scrollTo({ top: 0, behavior: "smooth" });
    });

    // ===== 4) Highlight menu theo section đang xem =====
    const menuLinks = Array.from(document.querySelectorAll("#menu a"));
    const sections = menuLinks
      .map(a => document.querySelector(a.getAttribute("href")))
      .filter(Boolean);

    function highlightMenu(){
      const y = window.scrollY + 120; // bù header
      let currentId = "home";

      sections.forEach(sec => {
        if(sec.offsetTop <= y) currentId = sec.id;
      });

      menuLinks.forEach(a => {
        const id = a.getAttribute("href").replace("#","");
        a.classList.toggle("active", id === currentId);
      });
    }
    highlightMenu();
  </script>

</body>
</html>
    

👉 Copy code → lưu thành bai15.html → mở bằng Chrome.
Cuộn trang để thấy menu active đổi theo section + nút “↑” hiện khi cuộn xuống.

✍️ Bài tập

  1. Đổi nội dung “Features” thành đúng khóa học của bạn (HTML/CSS/JS).
  2. Thêm section mới “Pricing” (bảng giá) và thêm vào menu.
  3. Đổi gallery thành ảnh thật (dùng <img>).
  4. (Nâng cao) Làm menu dạng nút hamburger trên mobile.

✅ Đáp án gợi ý

1) Thêm section Pricing (gợi ý)


<a href="#pricing">Pricing</a>

<section id="pricing">
  <h2>Pricing</h2>
  ...
</section>
    

Không có nhận xét nào:

Đăng nhận xét

Bài đăng phổ biến

💬 Bình luận

💬 Bình luận

📌 Danh sách bình luận