Xây dựng website bán hàng bằng HTML – CSS – JavaScript

10:59 15/12/2025

Trong bối cảnh thương mại điện tử phát triển mạnh mẽ, việc nắm vững các công nghệ web nền tảng như HTML, CSS và JavaScript là yêu cầu thiết yếu đối với sinh viên công nghệ thông tin. Bài viết dưới đây FPT Polytechnic TP HCM sẽ hướng dẫn chi tiết cách xây dựng website bán hàng bằng HTML – CSS – JavaScript.

Tổng quan bài toán

Mục tiêu: Xây dựng website bán điện gồm các chức năng:

  • Đăng nhập người dùng
  • Hiển thị sản phẩm
  • Thêm sản phẩm vào giỏ hàng
  • Cập nhật/xóa sản phẩm khỏi giỏ
  • Thanh toán đơn hàng
  • Xuất giỏ hàng ra Excel
  • Liên hệ và xác thực biểu mẫu
  • Hiệu ứng vieo: gallery và slider, button thao tác(next, last,…)
  • Media: phát nhạc nền lúc người dùng mở trang web

Cấu trúc toàn trang

HTML: Cấu trúc bố cục

<head>: Chứa meta thông tin (charset, viewport), tiêu đề trang (<title>), liên kết CSS (test.css, Font Awesome), và script.

<body>: 

<nav class=”navbar”> (Header/Navigation Bar):

  • Logo (logoContainer).
  • Menu điều hướng (navLinks với dropdown cho sản phẩm và liên hệ).
  • Thanh tìm kiếm (searchBar).
  • Nút Đăng Nhập/Đăng Ký (navButtons).

Modal Windows:

  • loginModal và registerModal cho chức năng đăng nhập/đăng ký.
  • musicModal hỏi người dùng có muốn bật nhạc nền không.

<section class=”banner”

  • Tiêu đề, mô tả, video background và nút điều khiển video

<section class=”stats”>

  • Hiển thị số liệu khách hàng, đơn hàng, người dùng online.

<section class=”productSection”>

  • Danh sách sản phẩm nổi bật (productContainer với các productCard).
  • Mỗi card sản phẩm gồm hình ảnh, tên, giá, nút “Buy Now” và popup tương tác (like, thêm giỏ hàng)

<footer>:

  • 4 cột thông tin: 
  • Mạng xã hội (Facebook, Discord, LeetCode).
  • Ví điện tử (Ngân hàng, Ví điện tử).
  • Dịch vụ (Đặt trước, Mua đồ cũ, Sửa chữa).
  • Lịch sử (Thanh toán, Đơn hàng).
  • Dòng bản quyền (footerBottom)

Scripts:

  • Liên kết file JavaScript (main.js).

Sơ đồ tổng quan:

CSS: Giao diện

1. Layout linh hoạt (Responsive) 

a. Flexbox/Grid:

  • Sử dụng flexbox cho navbar (navbar), product grid (productContainer), và footer (footerContainer).

Kích thước động:

  • width: 80% cho navbar và footer, max-width: 90% cho modal.
  • Sản phẩm (productCard) dùng calc(50% – 20px) để tự động co giãn.

b. Phối màu đẹp mắt

Gradient:

  • Navbar: linear-gradient(90deg, #c5cbd6, #d7dce5) (màu xám nhạt).
  • Modal/Section: linear-gradient(90deg, #1c2b44, #2a3b5e) (xanh đậm).
  • Nút: linear-gradient(90deg, #17c3fc, #00b4fc) (xanh dương).

Màu chữ:

  • Chính: white (nền tối), #1c2b44 (nền sáng).
  • Giá sản phẩm: red, #ff9800 (nổi bật).

c. Hiệu ứng hover và transition

Navbar:

  • Link đổi màu khi hover: color: #007bff.
  • Dropdown menu xuất hiện với opacity và transform.

Sản phẩm:

  • transform: scale(1.1) khi hover, kèm đổ bóng (box-shadow).
  • Icon tim/like/giỏ hàng đổi màu khi active (vd: tim đỏ #ff0015).

Nút:

  • transition: 0.3s cho opacity (vd: nút “Buy Now” mờ dần khi hover).

d. Bo góc và đổ bóng

Bo góc:

  • Navbar: border-radius: 50px.
  • Sản phẩm: border-radius: 15px.
  • Modal: border-radius: 15px.

Đổ bóng:

  • Navbar: box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2).
  • Sản phẩm: box-shadow: 0px 10px 20px rgba(0, 255, 255, 0.5) (hiệu ứng neon khi hover).

e. Định nghĩa thành phần quan trọng

Modal:

  • Background mờ (rgba(0, 0, 0, 0.7)), form căn giữa, input có viền trắng.

Product Gallery:

  • Lưới sản phẩm (productContainer) dùng flex-wrap: wrap để tự động xuống dòng.
  • Popup icon (tim/like/giỏ hàng) ẩn hiện với opacity: 0 → 1.

Form/Nút:

  • Nút “Buy Now” có padding: 12px 20px, gradient xanh.
  • Nút “Đăng Nhập” và “Đăng Ký” bo tròn (border-radius: 50px).

f. Hiệu ứng đặc biệt

Counter Animation:

  • Số liệu thống kê (khách hàng, đơn hàng) được tăng dần từ 0 bằng JS (không thấy code nhưng có ID counterCustomers, counterOrders).

Nhạc nền:

  • Modal hỏi ý kiến trước khi bật nhạc (#musicModal).

Notification:

  • Thông báo giỏ hàng (cartNotification) hiện lên từ dưới với animation fadeInOut.

JavaScript: Xử lý logic

LocalStorage

  • Xóa dữ liệu cũ: Khi trang tải (load), localStorage.clear() xóa toàn bộ dữ liệu cũ.
  • Lưu sản phẩm: Khi nhấn “Buy Now”, thông tin sản phẩm (tên, giá, ảnh) được lưu vào localStorage dưới key prodcutIn4 (để chuyển sang trang giỏ hàng).

Tương tác người dùng

  • Icon tim/giỏ hàng:
    • toggleIcon(): Đổi màu icon (thêm/xóa class active), hiện thông báo (vd: “Đã thêm vào giỏ hàng”).
    • Tim (heart): Đổi icon thành fa-heart-crack khi active.
  • Đăng ký/Đăng nhập:
    • Đăng ký: Kiểm tra email hợp lệ, mật khẩu trùng khớp, lưu vào mảng users.
    • Đăng nhập: So sánh với dữ liệu trong users, thông báo thành công hoặc lỗi.

Hiệu ứng động

  • Counter: Tăng dần số liệu (khách hàng, đơn hàng) với setInterval.
  • Video slider:
    • Tự động chuyển video khi kết thúc (onended).
    • Nút điều khiển (First/Prev/Next/Last) dùng changeVideo() để thay đổi currentVideoIndex.

Xử lý form & modal

  • Modal nhạc nền: Hiện sau 1 giây, lưu lựa chọn (bật/tắt nhạc) vào biến temp.
  • Đóng modal: Nút “×” ẩn modal đăng nhập/đăng ký.

Thu thập dữ liệu sản phẩm

  • Lặp qua các productCard, lấy tên/giá/ảnh và đẩy vào mảng productItems (log ra console).

Phân tích từng chức năng chính

Đăng nhập, đăng ký:

Tại sao?

  • Chức năng này giới hạn quyền truy cập, xác thực người dùng để quản lý giỏ hàng, đơn hàng và cá nhân hóa trải nghiệm (ví dụ: lưu lịch sử mua sắm). Nó hỗ trợ mục tiêu “Đăng nhập người dùng” trong Y1, giúp tăng tính bảo mật và trải nghiệm người dùng

Dữ Liệu:

  • Mảng users (trong main.js): Lưu trữ thông tin người dùng dưới dạng object {username, password, email}.
  • Không sử dụng cơ sở dữ liệu thực tế, chỉ lưu tạm trong bộ nhớ (mảng JS) và không lưu vào localStorage (dữ liệu mất khi reload trang).

Xử lý:

  • Đăng ký (registerModal): 
    • Form thu thập username, password, confirmPassword, email.
    • Kiểm tra: Không để trống, mật khẩu >=6 ký tự, mật khẩu khớp, email hợp lệ (chứa “@” và “.”).
    • Nếu hợp lệ, đẩy vào mảng users và hiển thị alert(“Đăng ký thành công!”). Modal đóng tự động.
    • Xử lý sự kiện: submit form trong main.js.
  • Đăng nhập (loginModal): 
    • Form thu thập username, password.
    • Kiểm tra: Không để trống, so sánh với mảng users.
    • Nếu khớp, alert(“Đăng nhập thành công!”). Nếu sai mật khẩu hoặc không tìm thấy, alert lỗi tương ứng.
    • Không lưu trạng thái đăng nhập (session/localStorage), nên người dùng phải đăng nhập lại mỗi lần reload.
  • Giao diện: Modal popup (CSS: background gradient xanh đậm, input trắng, nút xanh dương). Hiển thị/ẩn bằng style.display = “none”. 

Danh mục sản phẩm:

Dữ liệu:

  • Danh sách sản phẩm cứng (hard-coded) trong index.html: 6 sản phẩm (Samsung S25 Ultra, iPhone 16, Vivo X200 Pro, Xiaomi 15 Ultra, OPPO Find X8, Huawei Pura 80 Ultra). 
  • Mỗi sản phẩm: Tên, giá, hình ảnh, giảm giá (-20%), nút “Buy Now”. 
  • Mảng productItems (main.js): Thu thập dữ liệu sản phẩm từ DOM (tên, giá, ảnh) và log ra console (có thể dùng để xử lý sau).

Xử lý:

  • Hiển thị: Sử dụng lưới flex (productContainer trong test.css) để sắp xếp sản phẩm thành các card. Mỗi card có hình ảnh, tên, giá, giảm giá, nút tương tác (heart, like, open, cart). 
  • Tương tác: 

Hover: Hiển thị icon container (opacity 0 → 1) với hiệu ứng scale(1.1) và box-shadow neon.

Toggle icon (toggleIcon trong main.js): Thay đổi class “active”, đổi icon (ví dụ: heart → heart-crack), alert thông báo (tym, thêm giỏ hàng, like, tương tác).

“Buy Now”: Lưu sản phẩm vào localStorage (‘prodcutIn4’) dưới dạng JSON {name, price, img, amount:1} và chuyển sang GioHang.html.

  • Giao diện: Card bo góc, gradient nền, giá nổi bật màu cam (#ff9800), hiệu ứng hover neon (box-shadow rgba(0,255,255,0.5)). 
  • Hạn chế: Không có tìm kiếm sản phẩm (thanh searchBar chỉ là placeholder, không có logic JS). Không có thêm vào giỏ hàng từ icon (chỉ alert, không lưu thực tế trừ “Buy Now”).

Giỏ hàng:

Lưu trữ:

  • localStorage “cartItems”: Mảng JSON các sản phẩm {name, price, img, amount}. 
  • Nếu từ “Buy Now” (main.js): Lưu tạm vào “prodcutIn4”, sau đó merge vào “cartItems” khi tải GioHang.html.

Các chức năng:

  • Thêm sản phẩm: Từ “Buy Now” (index.html → GioHang.html). Nếu sản phẩm tồn tại, tăng amount; nếu không, push mới. 
  • Hiển thị giỏ (displayCart trong gioihang.js): Render bảng (cart-table) với cột: ảnh, tên, số lượng (controls +/-), giá gốc, giảm giá (20%), thành tiền, xóa. 

Tính toán: discount = price * 0.2, itemTotal = (price – discount) * amount.

Nếu giỏ rỗng: Hiển thị thông báo “Giỏ hàng của bạn đang trống” và disable nút checkout.

  • Cập nhật số lượng: Nút + (plus) tăng amount, nút – (minus) giảm (tối thiểu 1). Cập nhật localStorage và re-render. 
  • Xóa sản phẩm: Nút “Xoá” (delete-btn) splice item khỏi mảng, cập nhật localStorage và re-render. 
  • Giao diện: Bảng responsive (gioihang.css), nút +/- gradient xanh, xóa đỏ (#ff4d4d), tổng tiền trong cart-totals. 
  • Hạn chế: Không có xuất giỏ hàng ra Excel (tài liệu đề cập dùng xlsx.js nhưng mã không triển khai).

Thanh toán

Dữ Liệu:

  • Từ giỏ hàng: cartItems, tổng sản phẩm (proPrice), phí ship (20000 VND nếu giao nhà), tổng cộng (toalPrice). 
  • Form: Họ tên, số điện thoại, địa chỉ (nếu giao nhà), ghi chú.

Xử lí:

  • Chọn phương thức ship: Radio “Giao tận nhà” (+20000 VND, hiển thị form địa chỉ) hoặc “Nhận tại cửa hàng” (miễn phí, ẩn địa chỉ). Cập nhật totals khi change (updateShippingMethod). 
  • Xác thực form (validate trong gioihang.js): 

Bắt buộc: Tên (chữ cái + khoảng trắng), phone (0 theo sau 9-10 số), địa chỉ (10-100 ký tự nếu giao nhà), ghi chú (<=200 ký tự).

Nếu giỏ rỗng: Alert lỗi.

Lấy vị trí GPS (getLocationBtn): Sử dụng navigator.geolocation để lấy latitude/longitude và điền vào address.

  • Thanh toán (checkout): Lưu orderInfo {items, shipping, total, customerInfo} vào localStorage, alert thành công, chuyển sang Checkout.html (chưa có trong mã). 
  • Giao diện: Form gradient nền, nút checkout gradient cam (#ff9800), disable nếu giỏ rỗng. 
  • Hạn chế: Không có trang Checkout.html thực tế (chỉ redirect), không tích hợp thanh toán thật (ví dụ: API ngân hàng).

Liên hệ và xác thực form

Dữ liệu:

  • Không có form liên hệ riêng (footer có link Facebook, nhưng không form). Xác thực chỉ ở form đăng ký/đăng nhập và thanh toán.

Xử lý:

  • Xác thực: Như trên (regex cho tên/phone, length check cho địa chỉ/notes/email/password). 
  • Liên hệ: Footer có link mạng xã hội (Facebook, Discord, LeetCode) với icon hover scale(1.2). Không có form gửi liên hệ. 
  • Giao diện: Footer flex 4 cột, gradient trắng xám, icon màu #007bff khi hover. 
  • Hạn chế: Không có form liên hệ đầy đủ (tài liệu đề cập nhưng mã chưa có)

Hiệu ứng Video: Gallery và Slider, Button Thao tác

Dữ liệu:

  • Mảng videoSources (main.js): 6 video (.mp4) về sản phẩm.

Xử lý:

  • Slider: Video tự play, onended chuyển video tiếp theo (changeVideo). Nút: First (index 0), Prev (index -1), Next (index +1), Last (length-1). Vòng lặp modulo. 
  • Gallery: Không gallery ảnh riêng, nhưng sản phẩm có popup icon khi hover (heart/like/open/cart). 
  • Button thao tác: Click thay đổi src video và play. 
  • Giao diện: Video full-width, nút controls gradient xanh (#007bff). 
  • Hạn chế: Không gallery ảnh (tài liệu đề cập slider ảnh nhưng mã là video).

Media: Phát Nhạc Nền

Dữ liệu:

  • Mảng videoSources (main.js): 6 video (.mp4) về sản phẩm.

Xử lý:

  • Modal #musicModal hiện sau 1s (setTimeout). 
  • Nút “Có” (acceptMusic): Play nhạc, lưu temp=”accepted”. 
  • Nút “Không” (declineMusic): Ẩn modal, lưu temp=”declined”. 
  • Nếu temp=”accepted”, play tự động (nhưng mã có bug: kiểm tra sau khi click, không lưu persistent). 
  • Giao diện: Modal gradient, nút xanh (#4CAF50) và đỏ (#f44336). 
  • Hạn chế: Không lưu lựa chọn persistent (localStorage), modal hiện mỗi lần load.

Các bước xây dựng ứng dụng

B1: Chức năng Đăng nhập và Đăng ký

Mô tả: Xây dựng modal đăng nhập/đăng ký để xác thực người dùng. Dữ liệu lưu tạm trong mảng JS (users). Kiểm tra cơ bản: không trống, mật khẩu khớp, email hợp lệ. Không lưu persistent (mất khi reload). 


Bước thực hiện:

  1. HTML (index.html): Thêm modal cho login và register. 
  • Login modal: Form với id=”loginModal”, input username/password, nút submit.
  • Register modal: Form với id=”registerModal”, input username/password/confirmPassword/email, nút submit.
  • Thêm nút “Đăng Nhập” và “Đăng Ký” ở navbar để mở modal (display: block).

2. CSS (test.css): Style modal với background gradient (#1c2b44 → #2a3b5e), input trắng, nút xanh (#007bff). 

3. JS (main.js): 

  • Khởi tạo mảng let users = [];.
  • Submit register form: Lấy value, kiểm tra (if !username || !password…, password.length <6, password !== confirmPassword, email includes “@” và “.”), push vào users, alert thành công, ẩn modal.
  • Submit login form: Lấy value, find user trong mảng, so sánh password, alert thành công/sai.
  • Thêm event click cho nút login/register để ẩn modal sau submit.

4. Tích hợp: Kết nối form submit với event listener.

B2: Chức năng Slide Show (Video Slider)

Mô tả: Xây dựng slider video sản phẩm với nút điều khiển (First, Prev, Next, Last). Video tự play và chuyển khi ended. Không gallery ảnh, chỉ video như trong mã.

Bước thực hiện:

  1. HTML (index.html): 
  • Thêm section banner với <video id=”videoPlayer”> (src mặc định), và nút controls: id=”firstVideo”, “prevVideo”, “nextVideo”, “lastVideo”.</video> 

2. CSS (test.css): 

  • Video full-width, nút gradient xanh (#007bff), hover #0056b3. 

3. JS (main.js): 

  • Mảng videoSources = [“video/all.mp4”, … “video/invin.mp4”].
  • Biến currentVideoIndex = 0.
  • Hàm changeVideo(newIndex): Cập nhật index (modulo để vòng lặp), set src, play(). Thêm onended để chuyển next.
  • Event listener cho nút: firstVideo → changeVideo(0), prev → (index-1 + length) % length, next → (index+1) % length, last → length-1.
  • Khởi tạo: changeVideo(0).

B3: Chức năng Sản phẩm (Hiển thị và Tương tác)

Mô tả: Hiển thị danh sách sản phẩm nổi bật với card (tên, giá, ảnh, giảm -20%, nút Buy Now). Hover hiển thị icon tương tác (heart, like, cart, open).

Bước thực hiện:

  1. HTML (index.html):
  • Section productSection với các div.productCard: img, h3 tên, span.price, discount, nút.buyNow (attr: name, price, img), iconContainer với button heart/like/open/cart. 

2. CSS (test.css):

  • Card gradient, hover opacity iconContainer 1, scale 1.1. Icon active thay màu (#ff0015 cho heart…). 

3. JS (main.js): 

  • QueryAll .productCard, add event mouseenter/leave để toggle opacity iconContainer.
  • Hàm toggleIcon(btn): Toggle class “active”, alert tương ứng (tym, thêm giỏ…), thay icon (fa-heart → fa-heart-crack).
  • QueryAll .buyNow: Add event click → Lấy attr, tạo object {name, price, img, amount:1}, lưu JSON vào localStorage ‘prodcutIn4’, redirect ‘GioHang.html’.
  • Thu thập productItems từ DOM để console.log (có thể dùng sau cho search).

B4: Chức năng Giỏ hàng (Thêm, Cập nhật, Xóa)

Mô tả: Hiển thị bảng giỏ hàng từ localStorage, cập nhật số lượng, xóa, tính tổng (giảm 20%).

Bước thực hiện:

  1. HTML (GioHang.html):
  • Table id=”cart-table” (cột: ảnh, tên, quantity controls, giá, discount, total, xóa). Form shipping, info nhận hàng, totals, nút checkout. 

2. CSS (gioihang.css): 

  • Table responsive, nút +/- xanh, xóa đỏ, checkout cam. 

3. JS (gioihang.js): 

  • Load cartItems từ localStorage.
  • Nếu có ‘prodcutIn4’, merge vào cartItems (tăng amount nếu tồn tại).
  • Hàm displayCart(): Render tbody, tính discount/itemTotal/toalPrice/proPrice, update totals.
  • Event click table: delete-btn → splice, plus/minus → cập nhật amount (min 1).
  • Update localStorage sau mỗi thay đổi.

B5: Chức năng thanh toán

Mô tả: Chọn ship, nhập info, validate, lưu orderInfo, redirect Checkout.html (mô phỏng thanh toán).

Bước thực hiện:

  1. HTML (GioHang.html + Checkout.html):
  • Form shipping radio, input name/phone/address/notes, nút getLocation. Checkout: Chọn payment (COD, bank, MoMo), nút confirm. 

2. CSS (gioihang.css): 

  • Form gradient, nút xanh. 

3. JS (gioihang.js + checkOut.js): 

  • UpdateShippingMethod(): Change radio → Ẩn/hiện address, cập nhật phí ship (20000/0), totals.
  • GetLocation: navigator.geolocation → Điền lat/long vào address.
  • Checkout click: Validate (name regex chữ, phone 0+9-10 số, address 10-100 nếu ship nhà, notes <=200). Lưu orderInfo JSON vào localStorage, alert, redirect Checkout.html.
  • Checkout.js: (Hiện trống) Thêm event confirm → Alert thành công, redirect PaymentSuccess.html, xóa cartItems.

B6: Chức năng Liên hệ và Nhạc nền

Mô tả: Footer liên hệ (link social), modal nhạc nền. Không form liên hệ đầy đủ, chỉ link.

Bước thực hiện:

  1. HTML (index.html + all pages): 
  • Footer với 4 cột (Social, Wallet, Services, History). Music modal id=”musicModal” với nút accept/decline. 

2. CSS (test.css): 

  • Footer flex, icon hover scale 1.2, modal gradient. 

3. JS (main.js): 

  • SetTimeout 1000ms → Hiển thị musicModal.
  • Accept: Play #backgroundMusic, ẩn modal, temp=”accepted”.
  • Decline: Ẩn, temp=”declined”.
  • Kiểm tra temp để play (nhưng bug, thêm localStorage để persistent).
  • Footer link: Thêm href cho Facebook/Discord/LeetCode.

Dự án đã hoàn thiện một website bán hàng cơ bản sử dụng HTML, CSS và JavaScript, đạt được các mục tiêu từ Y1: đăng nhập người dùng, hiển thị và tương tác sản phẩm, quản lý giỏ hàng (thêm/cập nhật/xóa), thanh toán đơn hàng (mô phỏng với validate và redirect), liên hệ qua footer, hiệu ứng video slider với nút thao tác, và media nhạc nền với modal xác nhận. Giao diện responsive, thân thiện (gradient xanh đậm, neon hover), lưu trữ dữ liệu qua localStorage tiện lợi, và các hiệu ứng như toggle icon, geolocation cho địa chỉ.

Mặc dù còn hạn chế (không backend thực, không export Excel, bug nhỏ ở nhạc nền), . Nó chứng minh khả năng xây dựng ứng dụng động mà không cần framework phức tạp. Với các cải tiến từ Y5, website có thể mở rộng thành sản phẩm thực tế. Ngày hoàn thành: 11/08/2025 (dựa trên current date), phù hợp với copyright © 2025 trong mã nguồn.

Đây là một dự án thực hành ổn cho sinh viên đang học HTML – CSS – JavaScript.:

Link Github source

Link trang web được triển khai tại Github

Giảng viên Hà Văn Cử
Bộ môn Công nghệ thông tin
FPT Polytechnic TP HCM

Hỗ trợ tư vấn và giải đáp thông tin tuyển sinh FPT Polytechnic

Cùng chuyên mục

Đăng ký nhập học tại FPT Polytechnic 2026

  • Max. file size: 50 MB.
  • Max. file size: 50 MB.
  • Max. file size: 50 MB.