Hướng dẫn code giao diện Flash Sale hiện đại
Mình sẽ làm theo cấu trúc 3 file độc lập: index.html + style.css + script.js, giao diện Flash Sale hiện đại, responsive, có countdown, sản phẩm, progress tồn kho, giá sale, badge %, nút mua ngay và hiệu ứng tương tác.
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FLASH SALE - Ưu đãi đặc biệt</title>
<meta name="description" content="Flash Sale - Săn deal cực sốc, ưu đãi giới hạn mỗi ngày.">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="flash-sale">
<!-- TOP BAR -->
<div class="top-bar">
<div class="container top-bar-inner">
<div class="top-left">
<span class="live-dot"></span>
<span>FLASH SALE ĐANG DIỄN RA</span>
</div>
<div class="top-right">
<span>🔥 Deal giới hạn</span>
<span>⚡ Số lượng có hạn</span>
</div>
</div>
</div>
<!-- HERO -->
<section class="hero">
<div class="hero-glow glow-1"></div>
<div class="hero-glow glow-2"></div>
<div class="container hero-content">
<div class="hero-copy">
<div class="eyebrow">
<span>⚡</span>
SIÊU SALE HÔM NAY
</div>
<h1>
FLASH
<strong>SALE</strong>
</h1>
<p>
Săn ngay những sản phẩm nổi bật với mức giá
cực sốc. Ưu đãi chỉ diễn ra trong thời gian giới hạn.
</p>
<div class="hero-actions">
<a href="#products" class="btn btn-primary">
Săn deal ngay
<span>→</span>
</a>
<a href="#products" class="btn btn-outline">
Xem sản phẩm
</a>
</div>
</div>
<!-- COUNTDOWN -->
<div class="countdown-card">
<div class="countdown-header">
<span>⏰ KẾT THÚC SAU</span>
<span class="status">ĐANG DIỄN RA</span>
</div>
<div class="countdown" id="countdown">
<div class="time-box">
<strong id="days">00</strong>
<small>Ngày</small>
</div>
<span class="separator">:</span>
<div class="time-box">
<strong id="hours">00</strong>
<small>Giờ</small>
</div>
<span class="separator">:</span>
<div class="time-box">
<strong id="minutes">00</strong>
<small>Phút</small>
</div>
<span class="separator">:</span>
<div class="time-box">
<strong id="seconds">00</strong>
<small>Giây</small>
</div>
</div>
<div class="countdown-note">
⚡ Nhanh tay! Nhiều deal đang được săn
</div>
</div>
</div>
</section>
<!-- SALE INFO -->
<section class="sale-info">
<div class="container sale-info-grid">
<div class="info-item">
<div class="info-icon">🚚</div>
<div>
<strong>Giao hàng nhanh</strong>
<span>Đóng gói & xử lý nhanh chóng</span>
</div>
</div>
<div class="info-item">
<div class="info-icon">🔒</div>
<div>
<strong>Thanh toán an toàn</strong>
<span>Bảo mật thông tin khách hàng</span>
</div>
</div>
<div class="info-item">
<div class="info-icon">🎁</div>
<div>
<strong>Ưu đãi giới hạn</strong>
<span>Deal đặc biệt trong hôm nay</span>
</div>
</div>
<div class="info-item">
<div class="info-icon">⭐</div>
<div>
<strong>Sản phẩm chất lượng</strong>
<span>Được nhiều khách hàng lựa chọn</span>
</div>
</div>
</div>
</section>
<!-- PRODUCTS -->
<section class="products-section" id="products">
<div class="container">
<div class="section-heading">
<div>
<div class="section-label">
🔥 DEAL HOT
</div>
<h2>
Săn deal <span>giá sốc</span>
</h2>
<p>
Những sản phẩm nổi bật đang được giảm giá mạnh.
</p>
</div>
<div class="sale-progress">
<span>Đã bán hôm nay</span>
<strong><span id="soldTotal">128</span>/200 sản phẩm</strong>
<div class="total-progress">
<div id="totalProgress"></div>
</div>
</div>
</div>
<div class="products-grid">
<!-- PRODUCT -->
<article class="product-card">
<div class="product-image">
<span class="discount-badge">-40%</span>
<span class="hot-badge">
🔥 HOT
</span>
<div class="product-placeholder">
<span>🎧</span>
</div>
<button class="wishlist" aria-label="Yêu thích">
♡
</button>
</div>
<div class="product-body">
<div class="product-category">
ELECTRONICS
</div>
<h3>Tai nghe Bluetooth Pro Max</h3>
<div class="rating">
<span>★★★★★</span>
<small>(128)</small>
</div>
<div class="price">
<strong>599.000đ</strong>
<del>999.000đ</del>
</div>
<div class="sold">
<div class="sold-text">
<span>Đã bán 86</span>
<strong>86%</strong>
</div>
<div class="progress">
<div style="width:86%"></div>
</div>
</div>
<button class="buy-btn">
MUA NGAY
<span>→</span>
</button>
</div>
</article>
<!-- PRODUCT -->
<article class="product-card">
<div class="product-image">
<span class="discount-badge">-35%</span>
<span class="hot-badge">
🔥 HOT
</span>
<div class="product-placeholder">
<span>⌚</span>
</div>
<button class="wishlist">
♡
</button>
</div>
<div class="product-body">
<div class="product-category">
SMART DEVICE
</div>
<h3>Smart Watch Ultra Series</h3>
<div class="rating">
<span>★★★★★</span>
<small>(96)</small>
</div>
<div class="price">
<strong>899.000đ</strong>
<del>1.399.000đ</del>
</div>
<div class="sold">
<div class="sold-text">
<span>Đã bán 72</span>
<strong>72%</strong>
</div>
<div class="progress">
<div style="width:72%"></div>
</div>
</div>
<button class="buy-btn">
MUA NGAY
<span>→</span>
</button>
</div>
</article>
<!-- PRODUCT -->
<article class="product-card">
<div class="product-image">
<span class="discount-badge">-50%</span>
<span class="hot-badge">
⚡ SIÊU SALE
</span>
<div class="product-placeholder">
<span>💻</span>
</div>
<button class="wishlist">
♡
</button>
</div>
<div class="product-body">
<div class="product-category">
LAPTOP
</div>
<h3>Laptop UltraBook Pro 14</h3>
<div class="rating">
<span>★★★★★</span>
<small>(214)</small>
</div>
<div class="price">
<strong>12.990.000đ</strong>
<del>25.990.000đ</del>
</div>
<div class="sold">
<div class="sold-text">
<span>Đã bán 94</span>
<strong>94%</strong>
</div>
<div class="progress">
<div style="width:94%"></div>
</div>
</div>
<button class="buy-btn">
MUA NGAY
<span>→</span>
</button>
</div>
</article>
<!-- PRODUCT -->
<article class="product-card">
<div class="product-image">
<span class="discount-badge">-30%</span>
<span class="hot-badge">
🔥 HOT
</span>
<div class="product-placeholder">
<span>📱</span>
</div>
<button class="wishlist">
♡
</button>
</div>
<div class="product-body">
<div class="product-category">
SMARTPHONE
</div>
<h3>Smartphone X Pro 5G</h3>
<div class="rating">
<span>★★★★★</span>
<small>(187)</small>
</div>
<div class="price">
<strong>9.990.000đ</strong>
<del>14.290.000đ</del>
</div>
<div class="sold">
<div class="sold-text">
<span>Đã bán 61</span>
<strong>61%</strong>
</div>
<div class="progress">
<div style="width:61%"></div>
</div>
</div>
<button class="buy-btn">
MUA NGAY
<span>→</span>
</button>
</div>
</article>
</div>
<div class="view-all">
<button id="viewAllBtn">
Xem tất cả sản phẩm
<span>→</span>
</button>
</div>
</div>
</section>
<!-- CTA -->
<section class="cta">
<div class="container cta-content">
<div>
<span class="cta-label">⚡ FLASH SALE</span>
<h2>
Đừng để deal hot
<span>trôi qua!</span>
</h2>
<p>
Ưu đãi có thể kết thúc bất cứ lúc nào.
Số lượng sản phẩm Flash Sale là có hạn.
</p>
</div>
<a href="#products" class="btn btn-white">
Săn deal ngay →
</a>
</div>
</section>
<!-- FOOTER -->
<footer>
<div class="container footer-inner">
<div>
<strong>FLASH<span>SALE</span></strong>
<p>
Săn deal cực sốc mỗi ngày.
</p>
</div>
<div class="footer-copy">
© 2026 Flash Sale. All rights reserved.
</div>
</div>
</footer>
</div>
<!-- TOAST -->
<div class="toast" id="toast">
<span>✓</span>
<div>
<strong>Đã thêm vào giỏ hàng</strong>
<small>Sản phẩm đã được chọn</small>
</div>
</div>
<script src="script.js"></script>
</body>
</html>:root {
--primary: #ff1744;
--primary-dark: #d50032;
--secondary: #ff6d00;
--dark: #111318;
--text: #24262d;
--muted: #777b85;
--border: #ececf1;
--bg: #f7f7fa;
--white: #ffffff;
--radius: 20px;
--shadow: 0 15px 45px rgba(20, 20, 30, .08);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
scroll-behavior: smooth;
}
body {
font-family: "Be Vietnam Pro", sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
}
button,
a {
font-family: inherit;
}
button {
border: 0;
cursor: pointer;
}
a {
text-decoration: none;
color: inherit;
}
.container {
width: min(1200px, calc(100% - 40px));
margin: auto;
}
/* =========================
TOP BAR
========================= */
.top-bar {
background: #0d0e12;
color: #fff;
font-size: 12px;
}
.top-bar-inner {
min-height: 42px;
display: flex;
justify-content: space-between;
align-items: center;
}
.top-left,
.top-right {
display: flex;
align-items: center;
gap: 20px;
}
.live-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #ff1744;
box-shadow: 0 0 0 5px rgba(255, 23, 68, .15);
animation: pulse 1.5s infinite;
}
/* =========================
HERO
========================= */
.hero {
position: relative;
overflow: hidden;
color: #fff;
background:
radial-gradient(circle at 80% 20%, rgba(255, 109, 0, .35), transparent 30%),
linear-gradient(120deg, #9b002c, #f0003d 45%, #ff6d00);
}
.hero::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -1px;
height: 70px;
background: var(--bg);
clip-path: polygon(0 100%, 100% 100%, 100% 30%, 80% 70%, 60% 30%, 40% 70%, 20% 30%, 0 70%);
}
.hero-content {
position: relative;
z-index: 2;
min-height: 500px;
padding: 80px 0 100px;
display: grid;
grid-template-columns: 1.1fr .9fr;
align-items: center;
gap: 70px;
}
.hero-glow {
position: absolute;
border-radius: 50%;
filter: blur(5px);
opacity: .35;
}
.glow-1 {
width: 400px;
height: 400px;
background: #ffb000;
right: -120px;
top: -150px;
}
.glow-2 {
width: 300px;
height: 300px;
background: #7000ff;
left: -120px;
bottom: -180px;
}
.eyebrow {
width: fit-content;
padding: 7px 13px;
margin-bottom: 18px;
border: 1px solid rgba(255,255,255,.3);
background: rgba(255,255,255,.1);
border-radius: 999px;
font-size: 12px;
font-weight: 800;
letter-spacing: .08em;
}
.eyebrow span {
margin-right: 5px;
}
.hero h1 {
font-size: clamp(58px, 8vw, 105px);
line-height: .85;
font-weight: 900;
letter-spacing: -.06em;
}
.hero h1 strong {
display: block;
color: #ffd000;
text-shadow: 4px 5px 0 rgba(100, 0, 0, .2);
}
.hero-copy > p {
max-width: 580px;
margin: 25px 0;
color: rgba(255,255,255,.84);
font-size: 16px;
}
.hero-actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 12px;
min-height: 50px;
padding: 0 23px;
border-radius: 12px;
font-size: 13px;
font-weight: 800;
transition: .25s ease;
}
.btn-primary {
background: #fff;
color: var(--primary);
box-shadow: 0 12px 30px rgba(0,0,0,.15);
}
.btn-primary:hover {
transform: translateY(-3px);
}
.btn-outline {
border: 1px solid rgba(255,255,255,.4);
color: #fff;
background: rgba(255,255,255,.08);
}
.btn-outline:hover {
background: rgba(255,255,255,.16);
}
/* =========================
COUNTDOWN
========================= */
.countdown-card {
padding: 28px;
border-radius: 25px;
background: rgba(20, 10, 10, .25);
border: 1px solid rgba(255,255,255,.18);
backdrop-filter: blur(15px);
box-shadow: 0 30px 70px rgba(70, 0, 0, .2);
}
.countdown-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
font-size: 11px;
font-weight: 800;
letter-spacing: .08em;
}
.status {
padding: 5px 9px;
border-radius: 999px;
background: rgba(255,255,255,.15);
}
.countdown {
display: grid;
grid-template-columns: 1fr auto 1fr auto 1fr auto 1fr;
align-items: center;
gap: 7px;
}
.time-box {
padding: 15px 8px;
text-align: center;
border-radius: 15px;
background: rgba(255,255,255,.12);
}
.time-box strong {
display: block;
font-size: 34px;
line-height: 1;
font-weight: 900;
}
.time-box small {
display: block;
margin-top: 8px;
font-size: 9px;
opacity: .7;
text-transform: uppercase;
}
.separator {
font-size: 25px;
font-weight: 900;
opacity: .6;
}
.countdown-note {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid rgba(255,255,255,.12);
text-align: center;
font-size: 12px;
opacity: .85;
}
/* =========================
SALE INFO
========================= */
.sale-info {
position: relative;
z-index: 5;
margin-top: -5px;
}
.sale-info-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
background: #fff;
border: 1px solid var(--border);
border-radius: 18px;
box-shadow: var(--shadow);
overflow: hidden;
}
.info-item {
display: flex;
align-items: center;
gap: 13px;
padding: 22px;
border-right: 1px solid var(--border);
}
.info-item:last-child {
border-right: 0;
}
.info-icon {
width: 42px;
height: 42px;
flex: 0 0 42px;
display: grid;
place-items: center;
border-radius: 12px;
background: #fff0f3;
font-size: 18px;
}
.info-item strong,
.info-item span {
display: block;
}
.info-item strong {
font-size: 12px;
}
.info-item span {
margin-top: 2px;
color: var(--muted);
font-size: 10px;
}
/* =========================
PRODUCTS
========================= */
.products-section {
padding: 85px 0;
}
.section-heading {
display: flex;
justify-content: space-between;
align-items: end;
gap: 30px;
margin-bottom: 35px;
}
.section-label {
margin-bottom: 7px;
color: var(--primary);
font-size: 11px;
font-weight: 900;
letter-spacing: .1em;
}
.section-heading h2 {
font-size: clamp(30px, 4vw, 45px);
line-height: 1.15;
letter-spacing: -.04em;
}
.section-heading h2 span {
color: var(--primary);
}
.section-heading p {
margin-top: 8px;
color: var(--muted);
font-size: 13px;
}
.sale-progress {
width: 230px;
}
.sale-progress > span,
.sale-progress strong {
display: block;
font-size: 11px;
}
.sale-progress strong {
margin-top: 4px;
}
.total-progress {
height: 7px;
margin-top: 9px;
overflow: hidden;
border-radius: 999px;
background: #e7e7eb;
}
.total-progress div {
width: 64%;
height: 100%;
background: linear-gradient(90deg, #ff1744, #ff6d00);
border-radius: inherit;
transition: width .5s;
}
.products-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 18px;
}
.product-card {
position: relative;
overflow: hidden;
border: 1px solid var(--border);
border-radius: var(--radius);
background: #fff;
box-shadow: 0 5px 20px rgba(20,20,30,.04);
transition: .3s ease;
}
.product-card:hover {
transform: translateY(-7px);
box-shadow: 0 25px 55px rgba(20,20,30,.12);
}
.product-image {
position: relative;
height: 235px;
display: grid;
place-items: center;
overflow: hidden;
background: linear-gradient(145deg, #f5f5f7, #e8e8ed);
}
.product-placeholder {
width: 145px;
height: 145px;
display: grid;
place-items: center;
border-radius: 35px;
background: #fff;
box-shadow: 0 25px 50px rgba(0,0,0,.12);
font-size: 75px;
transition: .4s ease;
}
.product-card:hover .product-placeholder {
transform: scale(1.08) rotate(-3deg);
}
.discount-badge {
position: absolute;
z-index: 2;
left: 13px;
top: 13px;
padding: 6px 9px;
border-radius: 7px;
background: var(--primary);
color: #fff;
font-size: 11px;
font-weight: 900;
}
.hot-badge {
position: absolute;
z-index: 2;
right: 13px;
top: 13px;
padding: 6px 9px;
border-radius: 7px;
background: #fff;
color: var(--primary);
font-size: 9px;
font-weight: 900;
}
.wishlist {
position: absolute;
z-index: 3;
right: 13px;
bottom: 13px;
width: 36px;
height: 36px;
border-radius: 50%;
background: rgba(255,255,255,.95);
font-size: 21px;
color: #555;
box-shadow: 0 5px 15px rgba(0,0,0,.08);
transition: .2s;
}
.wishlist.active {
color: var(--primary);
}
.product-body {
padding: 20px;
}
.product-category {
margin-bottom: 5px;
color: #9b9da4;
font-size: 9px;
font-weight: 800;
letter-spacing: .1em;
}
.product-body h3 {
min-height: 48px;
font-size: 14px;
line-height: 1.5;
}
.rating {
display: flex;
align-items: center;
gap: 6px;
margin: 7px 0;
}
.rating span {
color: #ffb000;
font-size: 11px;
letter-spacing: -2px;
}
.rating small {
color: #9b9da4;
font-size: 9px;
}
.price {
display: flex;
align-items: baseline;
gap: 8px;
margin-top: 12px;
}
.price strong {
color: var(--primary);
font-size: 20px;
font-weight: 900;
}
.price del {
color: #a4a5aa;
font-size: 10px;
}
.sold {
margin-top: 14px;
}
.sold-text {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
color: #777;
font-size: 9px;
}
.sold-text strong {
color: var(--primary);
}
.progress {
height: 6px;
overflow: hidden;
border-radius: 999px;
background: #eee;
}
.progress div {
height: 100%;
border-radius: inherit;
background: linear-gradient(90deg, #ff1744, #ff6d00);
}
.buy-btn {
width: 100%;
height: 45px;
margin-top: 16px;
border-radius: 10px;
background: #111318;
color: #fff;
font-size: 11px;
font-weight: 900;
transition: .25s;
}
.buy-btn span {
margin-left: 8px;
}
.buy-btn:hover {
background: var(--primary);
transform: translateY(-2px);
}
/* =========================
VIEW ALL
========================= */
.view-all {
display: flex;
justify-content: center;
margin-top: 35px;
}
.view-all button {
padding: 13px 24px;
border: 1px solid #dddde3;
border-radius: 10px;
background: #fff;
color: #333;
font-size: 12px;
font-weight: 800;
transition: .2s;
}
.view-all button:hover {
border-color: var(--primary);
color: var(--primary);
}
/* =========================
CTA
========================= */
.cta {
padding: 65px 0;
background:
radial-gradient(circle at 80% 30%, rgba(255,109,0,.3), transparent 30%),
linear-gradient(110deg, #a50032, #ef003c);
color: #fff;
}
.cta-content {
display: flex;
justify-content: space-between;
align-items: center;
gap: 40px;
}
.cta-label {
font-size: 10px;
font-weight: 900;
letter-spacing: .1em;
}
.cta h2 {
max-width: 600px;
margin-top: 7px;
font-size: clamp(30px, 4vw, 45px);
line-height: 1.15;
}
.cta h2 span {
color: #ffd000;
}
.cta p {
max-width: 600px;
margin-top: 10px;
color: rgba(255,255,255,.75);
font-size: 13px;
}
.btn-white {
flex-shrink: 0;
background: #fff;
color: var(--primary);
}
/* =========================
FOOTER
========================= */
footer {
background: #0c0d10;
color: #fff;
}
.footer-inner {
min-height: 110px;
display: flex;
justify-content: space-between;
align-items: center;
}
.footer-inner strong {
font-size: 20px;
font-weight: 900;
}
.footer-inner strong span {
color: var(--primary);
}
.footer-inner p {
margin-top: 2px;
color: #858791;
font-size: 10px;
}
.footer-copy {
color: #666872;
font-size: 10px;
}
/* =========================
TOAST
========================= */
.toast {
position: fixed;
z-index: 9999;
right: 25px;
bottom: 25px;
display: flex;
align-items: center;
gap: 12px;
min-width: 290px;
padding: 15px 17px;
border-radius: 13px;
background: #111318;
color: #fff;
box-shadow: 0 20px 50px rgba(0,0,0,.25);
transform: translateY(130px);
opacity: 0;
pointer-events: none;
transition: .35s ease;
}
.toast.show {
transform: translateY(0);
opacity: 1;
}
.toast > span {
width: 30px;
height: 30px;
display: grid;
place-items: center;
border-radius: 50%;
background: #22c55e;
font-weight: 900;
}
.toast strong,
.toast small {
display: block;
}
.toast strong {
font-size: 11px;
}
.toast small {
margin-top: 2px;
color: #999;
font-size: 9px;
}
/* =========================
ANIMATION
========================= */
@keyframes pulse {
0%,100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(.65);
opacity: .5;
}
}
/* =========================
RESPONSIVE
========================= */
@media (max-width: 1000px) {
.hero-content {
grid-template-columns: 1fr;
gap: 40px;
}
.countdown-card {
max-width: 600px;
}
.sale-info-grid {
grid-template-columns: repeat(2, 1fr);
}
.info-item:nth-child(2) {
border-right: 0;
}
.info-item:nth-child(-n+2) {
border-bottom: 1px solid var(--border);
}
.products-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 650px) {
.container {
width: min(100% - 28px, 1200px);
}
.top-right {
display: none;
}
.hero-content {
padding: 55px 0 80px;
}
.hero h1 {
font-size: 70px;
}
.countdown-card {
padding: 18px;
}
.time-box strong {
font-size: 25px;
}
.sale-info-grid,
.products-grid {
grid-template-columns: 1fr;
}
.info-item {
border-right: 0;
border-bottom: 1px solid var(--border);
}
.info-item:last-child {
border-bottom: 0;
}
.section-heading {
display: block;
}
.sale-progress {
width: 100%;
margin-top: 25px;
}
.products-section {
padding: 60px 0;
}
.product-image {
height: 260px;
}
.cta-content {
display: block;
}
.cta .btn {
margin-top: 25px;
}
.footer-inner {
display: block;
padding: 30px 0;
}
.footer-copy {
margin-top: 20px;
}
.toast {
left: 14px;
right: 14px;
bottom: 14px;
min-width: 0;
}
}document.addEventListener("DOMContentLoaded", () => {
/* =========================
COUNTDOWN
========================= */
// Flash Sale kết thúc sau 24 giờ kể từ lúc mở trang
const saleEnd = new Date();
saleEnd.setHours(saleEnd.getHours() + 23);
saleEnd.setMinutes(saleEnd.getMinutes() + 59);
saleEnd.setSeconds(saleEnd.getSeconds() + 59);
const daysEl = document.getElementById("days");
const hoursEl = document.getElementById("hours");
const minutesEl = document.getElementById("minutes");
const secondsEl = document.getElementById("seconds");
function updateCountdown() {
const now = new Date();
const distance = saleEnd - now;
if (distance <= 0) {
daysEl.textContent = "00";
hoursEl.textContent = "00";
minutesEl.textContent = "00";
secondsEl.textContent = "00";
return;
}
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor(
(distance / (1000 * 60 * 60)) % 24
);
const minutes = Math.floor(
(distance / (1000 * 60)) % 60
);
const seconds = Math.floor(
(distance / 1000) % 60
);
daysEl.textContent = String(days).padStart(2, "0");
hoursEl.textContent = String(hours).padStart(2, "0");
minutesEl.textContent = String(minutes).padStart(2, "0");
secondsEl.textContent = String(seconds).padStart(2, "0");
}
updateCountdown();
setInterval(updateCountdown, 1000);
/* =========================
WISHLIST
========================= */
document.querySelectorAll(".wishlist").forEach(button => {
button.addEventListener("click", () => {
button.classList.toggle("active");
if (button.classList.contains("active")) {
button.innerHTML = "♥";
} else {
button.innerHTML = "♡";
}
});
});
/* =========================
BUY BUTTON
========================= */
const toast = document.getElementById("toast");
let toastTimer;
document.querySelectorAll(".buy-btn").forEach(button => {
button.addEventListener("click", () => {
button.classList.add("clicked");
showToast();
setTimeout(() => {
button.classList.remove("clicked");
}, 300);
});
});
function showToast() {
toast.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(() => {
toast.classList.remove("show");
}, 3000);
}
/* =========================
VIEW ALL
========================= */
const viewAllBtn = document.getElementById("viewAllBtn");
viewAllBtn.addEventListener("click", () => {
const cards = document.querySelectorAll(".product-card");
cards.forEach((card, index) => {
card.style.animation = "none";
setTimeout(() => {
card.style.transform = "translateY(-4px)";
setTimeout(() => {
card.style.transform = "";
}, 150);
}, index * 70);
});
viewAllBtn.innerHTML = "✓ Đang hiển thị tất cả";
setTimeout(() => {
viewAllBtn.innerHTML = 'Xem tất cả sản phẩm <span>→</span>';
}, 1800);
});
/* =========================
RANDOM SOLD COUNTER
TẠO CẢM GIÁC LIVE
========================= */
let sold = 128;
const soldTotal = document.getElementById("soldTotal");
const totalProgress = document.getElementById("totalProgress");
function increaseSold() {
if (sold >= 200) return;
const increase = Math.random() > .65 ? 2 : 1;
sold = Math.min(200, sold + increase);
soldTotal.textContent = sold;
const percent = (sold / 200) * 100;
totalProgress.style.width = percent + "%";
}
// Tăng số lượng đã bán ngẫu nhiên
setInterval(increaseSold, 7000);
/* =========================
PRODUCT CARD REVEAL
========================= */
const observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = "1";
entry.target.style.transform = "translateY(0)";
observer.unobserve(entry.target);
}
});
},
{
threshold: .12
}
);
document.querySelectorAll(".product-card").forEach(card => {
card.style.opacity = "0";
card.style.transform = "translateY(25px)";
card.style.transition =
"opacity .6s ease, transform .6s ease, box-shadow .3s ease";
observer.observe(card);
});
/* =========================
SMOOTH ANCHOR
========================= */
document.querySelectorAll('a[href^="#"]').forEach(link => {
link.addEventListener("click", event => {
const targetId = link.getAttribute("href");
if (targetId === "#") return;
const target = document.querySelector(targetId);
if (!target) return;
event.preventDefault();
target.scrollIntoView({
behavior: "smooth",
block: "start"
});
});
});
});
Ctrl1 HTML
Ctrl2 CSS
Ctrl3 JS
Ctrl↵ Reload