0

[Series 100 Bài Học HTML/CSS Thực Chiến - Bài 20]: Khởi Động Chương 7 — Giải Phẫu Trang Chi Tiết Sản Phẩm (Product Detail Page), Chọn Phân Loại Hàng Có Góc Tích 3D & Bộ Tăng Giảm Số Lượng

Chào mừng anh em đã chạm tới cột mốc Bài 20 (hoàn thành 15\frac{1}{5} chặng đường!) trong chuỗi 100 Bài Học Làm Chủ HTML/CSS Qua Dự Án Clone Shopee!

Ở Chương 6 (Bài 18 – 19), chúng ta đã hoàn thành giao diện Trang Danh Mục & Tìm Kiếm Sản Phẩm. Vậy điều gì xảy ra tiếp theo khi khách hàng ưng ý một chiếc Bàn phím cơ hay MacBook và click chuột vào thẻ sản phẩm đó? Họ sẽ được đưa tới "phòng chốt đơn" quan trọng nhất của toàn bộ hệ thống Thương mại điện tử: Trang Chi Tiết Sản Phẩm (Product Detail Page - PDP)!

Nếu mở bất kỳ sản phẩm nào trên Shopee, bạn sẽ thấy khối thông tin chính (Product Brief) được đặt trong một khung nền trắng rộng 1200px, chia làm 2 cột bất đối xứng (450px bên trái : Phần còn lại bên phải) với hàng loạt chi tiết kỹ thuật UI/UX cực kỳ đắt giá:

  1. Cột Trái (450px - Thư viện ảnh Product Gallery): Gồm 1 khung ảnh vuông lớn (450x450px) ở trên và dãy 5 ảnh Thumbnail nhỏ nằm ngang bên dưới. Khi rê chuột vào ảnh nhỏ nào, ảnh đó lập tức nổi viền cam #ee4d2d sắc nét!

  2. Cột Phải (flex: 1 - Khu vực Chốt Đơn):

    • Dòng thông số uy tín: Điểm sao (4.9 ★★★★★) | 1,2k Đánh Giá | 4,5k Đã Bán ngăn cách bằng vạch kẻ dọc.

    • Nút Chọn Phân Loại Hàng (Variant Swatch Button): Khi người dùng bấm chọn màu sắc hoặc phiên bản (ví dụ: Trắng Xanh - Reaper Switch), nút bấm không chỉ đổi sang viền cam mà ở góc dưới bên phải của nút còn xuất hiện một hình tam giác màu cam kèm dấu tích trắng (✓) nhỏ xíu!

    • Bộ điều khiển Số Lượng (Quantity Stepper: [-][ 1 ][+]): Hai nút cộng trừ ghép liền khối với ô nhập số ở giữa mà không bị dày viền gấp đôi.

    • Cặp Nút Hành Động Kép (Dual CTA Buttons): Nút "Thêm Vào Giỏ Hàng" (nền cam phấn nhạt, viền cam) đặt cạnh nút "Mua Ngay" (nền cam đậm, chữ trắng) theo đúng nguyên lý phân cấp thị giác!

Hãy cùng mổ xẻ và tự tay code toàn bộ khu vực "hái ra tiền" này ngay trong Bài 20!

1. Tư duy bố cục Trang Chi Tiết Sản Phẩm & Bí thuật vẽ "Góc Tích Tam Giác" trên nút Phân Loại Hàng

Trong thiết kế hệ thống E-Commerce, mỗi màn hình từ Trang tìm kiếm (Product Search), Giỏ hàng (Cart) cho đến bố cục chia 2 cột Trái - Phải đều tuân theo những khuôn mẫu Wireframe chuẩn mực để tối ưu tỷ lệ chuyển đổi:

image.png

Trên khung Product Brief của Shopee, chi tiết khiến nhiều bạn học viên thích thú (và cũng đau đầu nhất khi tự code) chính là Nút chọn Phân loại hàng khi đang ở trạng thái được chọn (Active / Selected):

Plaintext

+-----------------------------------+
|  Trắng Xanh - Reaper Switch       |  <-- Viền ngoài: border: 1px solid #ee4d2d
|                                 / |
|                               / ✓ |  <-- Góc dưới-phải: Tam giác cam 15x15px + Dấu tích trắng!
+-----------------------------/-----+

Làm thế nào để vẽ được cả miếng tam giác màu cam lẫn dấu tích trắng (✓) nằm gọn trong góc dưới bên phải của chiếc nút bấm mà không cần dùng ảnh .png? Chúng ta kết hợp cả 2 phần tử giả ::before và ::after trên nút .variation-btn--selected (hoặc dùng input:checked + .variation-btn):

Thành phần góc nút Phần tử sử dụng Kỹ thuật CSS thực chiến
Miếng tam giác vuông màu cam ở góc dưới-phải .variation-btn::before Đặt position: absolute; right: 0; bottom: 0;. Dùng thủ thuật border tạo tam giác vuông 1.5rem (15px): border-width: 1.5rem 0 0 1.5rem; với border-color: transparent transparent transparent var(--shopee-primary); (hoặc dùng clip-path).
Dấu tích trắng (✓) nằm đè lên tam giác cam .variation-btn::after Đặt content: "\2713"; (Mã Unicode của ký tự dấu tích ✓!), position: absolute; right: 0.1rem; bottom: -0.1rem;, cỡ chữ siêu nhỏ font-size: 0.8rem; color: #fff;!

Tại sao dùng content: "\2713" trong ::after lại cực kỳ thông minh?

Bạn không cần phải chèn thêm thẻ <i class="fa-solid fa-check"></i> vào trong từng nút HTML! Chỉ cần gắn class .variation-btn--selected (hoặc tích vào nút Radio), CSS sẽ tự động sinh ra cả miếng tam giác cam (::before) lẫn dấu tích trắng (::after) chỉ trong 1 nốt nhạc!

2. Phân cấp thị giác cặp nút "Thêm Vào Giỏ Hàng" vs "Mua Ngay"

Hãy nhìn vào 2 nút bấm lớn nhất ở cuối khu vực chọn hàng:

  1. Nút "Thêm Vào Giỏ Hàng" (Secondary CTA): Mang nền cam phấn cực nhạt (rgba(238, 77, 45, 0.08)), viền cam 1px solid #ee4d2d và chữ màu cam.

  2. Nút "Mua Ngay" (Primary CTA): Mang nền cam đặc #ee4d2d và chữ màu trắng rực rỡ.

Nếu cả hai nút đều tô nền cam đặc giống nhau, mắt người dùng sẽ bị phân vân không biết nên bấm nút nào trước (Hiệu ứng Choice Paralysis trong tâm lý học). Việc làm dịu nút "Thêm Vào Giỏ Hàng" thành dạng Tinted Outline Button và dồn 100% độ tương phản cho nút "Mua Ngay" giúp thúc đẩy hành vi thanh toán tức thì của khách hàng!

3. Thực hành: Code Khối Chi Tiết Sản Phẩm (Product Detail Brief) Chuẩn Shopee

Để bạn có thể xem và tương tác trực tiếp ngay trên dự án hiện tại, hãy mở file index.html và chèn khối <section class="product-detail-section"> vào bên trong <div class="shopee-container grid-container"> (ngay phía trên khu vực Chương 6 hoặc dưới Flash Sale):

Bước 1: Bổ sung HTML Trang Chi Tiết Sản Phẩm vào index.html

HTML

        <!-- ================================================================= -->
        <!-- CHƯƠNG 7: GIAO DIỆN CHI TIẾT SẢN PHẨM (PRODUCT DETAIL PAGE - PDP) -->
        <!-- ================================================================= -->
        <section class="product-detail-section">
            
            <!-- 1. Thanh đường dẫn Breadcrumb dẫn hướng -->
            <nav class="breadcrumb" aria-label="Breadcrumb">
                <a href="#" class="breadcrumb__link">Shopee</a>
                <i class="breadcrumb__icon fa-solid fa-chevron-right"></i>
                <a href="#" class="breadcrumb__link">Máy Tính &amp; Laptop</a>
                <i class="breadcrumb__icon fa-solid fa-chevron-right"></i>
                <a href="#" class="breadcrumb__link">Phụ Kiện Máy Tính</a>
                <i class="breadcrumb__icon fa-solid fa-chevron-right"></i>
                <span class="breadcrumb__current">Bàn phím cơ không dây AULA F75 Pro 3 Mode Hotswap</span>
            </nav>

            <!-- 2. Khung trắng chính chia 2 cột: Thư viện ảnh (Trái) & Thông tin mua hàng (Phải) -->
            <div class="product-briefing">
                
                <!-- CỘT TRÁI (450PX): THƯ VIỆN ẢNH SẢN PHẨM (PRODUCT GALLERY) -->
                <div class="product-gallery">
                    <!-- Khung ảnh lớn 1:1 -->
                    <div class="product-gallery__main">
                        <img src="https://placehold.co/600x600/ee4d2d/ffffff?text=AULA+F75+PRO+(Main+View)" alt="Bàn phím cơ AULA F75 Pro" class="product-gallery__main-img">
                    </div>

                    <!-- Dãy 5 ảnh Thumbnail nhỏ bên dưới -->
                    <ul class="product-gallery__thumbs">
                        <li class="product-gallery__thumb-item product-gallery__thumb-item--active">
                            <img src="https://placehold.co/150x150/ee4d2d/ffffff?text=Goc+1" alt="Góc chụp 1" class="product-gallery__thumb-img">
                        </li>
                        <li class="product-gallery__thumb-item">
                            <img src="https://placehold.co/150x150/00bfa5/ffffff?text=Switch" alt="Reaper Switch" class="product-gallery__thumb-img">
                        </li>
                        <li class="product-gallery__thumb-item">
                            <img src="https://placehold.co/150x150/2673dd/ffffff?text=LED+RGB" alt="Đèn LED RGB" class="product-gallery__thumb-img">
                        </li>
                        <li class="product-gallery__thumb-item">
                            <img src="https://placehold.co/150x150/ff9800/ffffff?text=Keycap" alt="Keycap PBT" class="product-gallery__thumb-img">
                        </li>
                        <li class="product-gallery__thumb-item">
                            <img src="https://placehold.co/150x150/7b1fa2/ffffff?text=Full+Box" alt="Phụ kiện trong hộp" class="product-gallery__thumb-img">
                        </li>
                    </ul>

                    <!-- Dòng Chia sẻ mạng xã hội & Đã thích ở đáy cột ảnh -->
                    <div class="product-gallery__share">
                        <div class="product-share-social">
                            <span>Chia sẻ:</span>
                            <a href="#" class="share-icon share-icon--fm"><i class="fa-brands fa-facebook-messenger"></i></a>
                            <a href="#" class="share-icon share-icon--fb"><i class="fa-brands fa-facebook"></i></a>
                            <a href="#" class="share-icon share-icon--pi"><i class="fa-brands fa-pinterest"></i></a>
                        </div>
                        <div class="product-like-btn">
                            <i class="fa-regular fa-heart product-like-icon"></i>
                            <span>Đã thích (3,4k)</span>
                        </div>
                    </div>
                </div>

                <!-- CỘT PHẢI (FLEX: 1): THÔNG TIN CHI TIẾT, PHÂN LOẠI & CHỐT ĐƠN -->
                <div class="product-summary">
                    
                    <!-- Tên sản phẩm kèm nhãn Yêu Thích ở ngay đầu dòng -->
                    <h1 class="product-summary__title">
                        <span class="product-summary__badge">Yêu thích+</span>
                        Bàn phím cơ không dây AULA F75 Pro 3 Mode (Bluetooth / 2.4G / Type-C) Mạch Xuôi Hotswap 5 Pin Đèn LED RGB 16.8 Triệu Màu
                    </h1>

                    <!-- Dải thông số: Điểm sao | Đánh giá | Đã bán -->
                    <div class="product-summary__metrics">
                        <div class="metric-item">
                            <span class="metric-rating-score">4.9</span>
                            <div class="metric-stars">
                                <i class="fa-solid fa-star"></i>
                                <i class="fa-solid fa-star"></i>
                                <i class="fa-solid fa-star"></i>
                                <i class="fa-solid fa-star"></i>
                                <i class="fa-solid fa-star"></i>
                            </div>
                        </div>
                        <div class="metric-item">
                            <span class="metric-count">1,2k</span>
                            <span class="metric-label">Đánh Giá</span>
                        </div>
                        <div class="metric-item">
                            <span class="metric-count">4,5k</span>
                            <span class="metric-label">Đã Bán</span>
                        </div>
                        <a href="#" class="metric-report">Tố cáo</a>
                    </div>

                    <!-- Khung Giá bán nền xám nhạt kèm Nhãn giảm giá -->
                    <div class="product-summary__price-box">
                        <span class="summary-price-old">₫1.390.000</span>
                        <span class="summary-price-current">₫850.000</span>
                        <span class="summary-price-discount">39% GIẢM</span>
                    </div>

                    <!-- Khu vực các dòng thuộc tính chọn lựa (Dùng Grid 2 cột: Nhãn 110px + Nội dung 1fr) -->
                    <div class="product-summary__options">
                        
                        <!-- Dòng 1: Mã giảm giá của Shop -->
                        <div class="option-row">
                            <span class="option-label">Mã Giảm Giá Của Shop</span>
                            <div class="option-content">
                                <span class="mini-voucher">Giảm ₫30k</span>
                                <span class="mini-voucher">Giảm ₫50k</span>
                                <span class="mini-voucher">Giảm 10%</span>
                            </div>
                        </div>

                        <!-- Dòng 2: Vận chuyển -->
                        <div class="option-row">
                            <span class="option-label">Vận Chuyển</span>
                            <div class="option-content shipping-info">
                                <i class="fa-solid fa-truck-fast shipping-icon"></i>
                                <div>
                                    <p class="shipping-free-title">Miễn phí vận chuyển</p>
                                    <p class="shipping-free-sub">Miễn phí vận chuyển cho đơn hàng trên ₫0</p>
                                </div>
                            </div>
                        </div>

                        <!-- Dòng 3: Chọn Màu Sắc (Dùng Radio Hack để bấm đổi nút có Góc Tích 3D!) -->
                        <div class="option-row">
                            <span class="option-label">Màu Sắc</span>
                            <div class="option-content variation-list">
                                <!-- Lựa chọn 1 (Đang được chọn mặc định) -->
                                <label class="variation-item">
                                    <input type="radio" name="product-color" class="variation-input" checked>
                                    <span class="variation-btn">Trắng Xanh (Ice Vein)</span>
                                </label>
                                <!-- Lựa chọn 2 -->
                                <label class="variation-item">
                                    <input type="radio" name="product-color" class="variation-input">
                                    <span class="variation-btn">Đen Vàng (Reaper Switch)</span>
                                </label>
                                <!-- Lựa chọn 3 -->
                                <label class="variation-item">
                                    <input type="radio" name="product-color" class="variation-input">
                                    <span class="variation-btn">Tím Hồng Pastel</span>
                                </label>
                                <!-- Lựa chọn 4 (Hết hàng - Disabled) -->
                                <label class="variation-item">
                                    <input type="radio" name="product-color" class="variation-input" disabled>
                                    <span class="variation-btn variation-btn--disabled">Xanh Matcha (Hết)</span>
                                </label>
                            </div>
                        </div>

                        <!-- Dòng 4: Chọn Số Lượng (Quantity Stepper) -->
                        <div class="option-row">
                            <span class="option-label">Số Lượng</span>
                            <div class="option-content quantity-row">
                                <div class="quantity-stepper">
                                    <button type="button" class="quantity-btn" aria-label="Giảm số lượng">
                                        <i class="fa-solid fa-minus"></i>
                                    </button>
                                    <input type="text" class="quantity-input" value="1" aria-label="Số lượng mua">
                                    <button type="button" class="quantity-btn" aria-label="Tăng số lượng">
                                        <i class="fa-solid fa-plus"></i>
                                    </button>
                                </div>
                                <span class="stock-available">482 sản phẩm có sẵn</span>
                            </div>
                        </div>

                    </div>

                    <!-- Cụm 2 Nút Hành Động Chốt Đơn: Thêm Vào Giỏ Hàng & Mua Ngay -->
                    <div class="product-summary__actions">
                        <button type="button" class="btn btn-add-to-cart">
                            <i class="fa-solid fa-cart-plus"></i>
                            <span>Thêm Vào Giỏ Hàng</span>
                        </button>
                        <button type="button" class="btn btn--primary btn-buy-now">
                            Mua Ngay
                        </button>
                    </div>

                    <!-- Dải cam kết Shopee Đảm Bảo ở dưới đáy -->
                    <div class="product-summary__guarantee">
                        <div class="guarantee-item">
                            <i class="fa-solid fa-Rotate-left guarantee-icon"></i>
                            <span>Trả hàng miễn phí 15 ngày</span>
                        </div>
                        <div class="guarantee-item">
                            <i class="fa-solid fa-shield-heart guarantee-icon"></i>
                            <span>Chính hãng 100%</span>
                        </div>
                        <div class="guarantee-item">
                            <i class="fa-solid fa-truck guarantee-icon"></i>
                            <span>Miễn phí vận chuyển</span>
                        </div>
                    </div>

                </div>

            </div>
        </section>

Bước 2: Viết CSS chi tiết cho Trang Chi Tiết Sản Phẩm trong ./assets/css/main.css

Hãy mở file main.css, cuộn xuống dưới cùng và bổ sung đoạn code CSS của Chương 7 dưới đây:

CSS

/* Bổ sung vào cuối file ./assets/css/main.css */

/* --- CHƯƠNG 7 (BÀI 20): TRANG CHI TIẾT SẢN PHẨM (PRODUCT DETAIL PAGE) --- */

.product-detail-section {
    margin-top: 2rem;
    margin-bottom: 3rem;
}

/* 1. Thanh đường dẫn Breadcrumb */
.breadcrumb {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    font-size: 1.3rem;
    margin-bottom: 1.6rem;
}

.breadcrumb__link {
    color: #0055aa;                 /* Màu xanh link điều hướng đặc trưng của Breadcrumb Shopee */
}

.breadcrumb__icon {
    font-size: 1rem;
    color: var(--text-secondary);
}

.breadcrumb__current {
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* 2. Khung trắng Product Briefing (Chia 2 cột: Trái 450px - Phải flex: 1) */
.product-briefing {
    background-color: var(--white-color);
    border-radius: 2px;
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
    display: flex;
    padding: 1.5rem;
    gap: 3.5rem;                    /* Khoảng cách 35px giữa cột Ảnh và cột Thông tin */
}

/* --- CỘT TRÁI: THƯ VIỆN ẢNH (PRODUCT GALLERY - 450PX) --- */
.product-gallery {
    width: 45rem;                   /* Cố định 450px chuẩn Shopee PC */
    flex-shrink: 0;
}

.product-gallery__main {
    width: 100%;
    aspect-ratio: 1 / 1;
    border-radius: 2px;
    overflow: hidden;
    border: 1px solid rgba(0, 0, 0, 0.05);
}

.product-gallery__main-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Dãy 5 ảnh Thumbnail nhỏ bên dưới */
.product-gallery__thumbs {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 1rem;
    margin-top: 1.2rem;
}

.product-gallery__thumb-item {
    aspect-ratio: 1 / 1;
    border: 2px solid transparent;  /* Đặt sẵn viền trong suốt 2px để khi hover không bị giật */
    border-radius: 2px;
    overflow: hidden;
    cursor: pointer;
    transition: border-color 0.15s ease;
}

/* Khi ảnh nhỏ đang Active hoặc khi rê chuột vào -> Lên viền Cam Shopee 2px! */
.product-gallery__thumb-item--active,
.product-gallery__thumb-item:hover {
    border-color: var(--shopee-primary);
}

.product-gallery__thumb-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Dòng Chia sẻ & Đã thích dưới đáy cột ảnh */
.product-gallery__share {
    display: flex;
    align-items: center;
    justify-content: space-around;
    margin-top: 2.4rem;
    padding-top: 1.2rem;
}

.product-share-social {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1.5rem;
}

.share-icon {
    font-size: 2.2rem;
}

.share-icon--fm { color: #0384ff; }
.share-icon--fb { color: #3b5999; }
.share-icon--pi { color: #de0217; }

.product-like-btn {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    font-size: 1.5rem;
    padding-left: 3rem;
    border-left: 1px solid rgba(0, 0, 0, 0.09);
    cursor: pointer;
}

.product-like-icon {
    font-size: 2rem;
    color: #ff424f;
}

/* --- CỘT PHẢI: THÔNG TIN CHI TIẾT & CHỐT ĐƠN (PRODUCT SUMMARY) --- */
.product-summary {
    flex: 1;
    padding: 0.5rem 2rem 0 0;
}

.product-summary__title {
    font-size: 2rem;
    font-weight: 500;
    line-height: 2.6rem;
    color: var(--text-primary);
}

.product-summary__badge {
    background-color: var(--shopee-primary);
    color: var(--white-color);
    font-size: 1.2rem;
    font-weight: 500;
    padding: 0.2rem 0.6rem;
    border-radius: 2px;
    vertical-align: middle;
    margin-right: 0.8rem;
    position: relative;
    top: -0.2rem;
}

/* Dải thông số: 4.9 Sao | 1,2k Đánh Giá | 4,5k Đã Bán */
.product-summary__metrics {
    display: flex;
    align-items: center;
    margin-top: 1.4rem;
}

.metric-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0 1.6rem;
    border-right: 1px solid rgba(0, 0, 0, 0.14);
}

.metric-item:first-child {
    padding-left: 0;
}

.metric-item:nth-child(3) {
    border-right: none;
}

.metric-rating-score {
    font-size: 1.6rem;
    color: var(--shopee-primary);
    border-bottom: 1px solid var(--shopee-primary);
    font-weight: 500;
}

.metric-stars {
    color: var(--shopee-primary);
    font-size: 1.3rem;
    display: flex;
    gap: 0.2rem;
}

.metric-count {
    font-size: 1.6rem;
    color: var(--text-primary);
    border-bottom: 1px solid var(--text-primary);
}

.metric-label {
    font-size: 1.4rem;
    color: var(--text-secondary);
}

.metric-report {
    margin-left: auto;              /* Đẩy chữ "Tố cáo" sang sát mép phải */
    font-size: 1.4rem;
    color: var(--text-secondary);
}

/* Khung Giá bán nền xám #fafafa */
.product-summary__price-box {
    background-color: #fafafa;
    padding: 1.5rem 2rem;
    margin-top: 1.6rem;
    border-radius: 2px;
    display: flex;
    align-items: center;
    gap: 1.4rem;
}

.summary-price-old {
    font-size: 1.6rem;
    color: #929292;
    text-decoration: line-through;
}

.summary-price-current {
    font-size: 3rem;                /* Giá chính to 30px cực kỳ nổi bật */
    font-weight: 500;
    color: var(--shopee-primary);
}

.summary-price-discount {
    background-color: var(--shopee-primary);
    color: var(--white-color);
    font-size: 1.2rem;
    font-weight: 700;
    padding: 0.2rem 0.6rem;
    border-radius: 2px;
    text-transform: uppercase;
}

/* Khu vực các dòng thuộc tính (Voucher, Vận chuyển, Màu sắc, Số lượng) */
.product-summary__options {
    margin-top: 2.4rem;
    padding: 0 2rem;
    display: flex;
    flex-direction: column;
    gap: 2.4rem;
}

/* Mỗi dòng thuộc tính dùng Grid 2 cột: Cột nhãn 110px + Cột nội dung 1fr */
.option-row {
    display: grid;
    grid-template-columns: 11rem 1fr;
    align-items: center;
}

.option-label {
    font-size: 1.4rem;
    color: #757575;
}

.option-content {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.8rem;
}

/* Thẻ Mini Voucher */
.mini-voucher {
    background-color: var(--shopee-primary-light);
    color: var(--shopee-primary);
    font-size: 1.3rem;
    padding: 0.3rem 0.8rem;
    border-radius: 2px;
    border: 1px dashed var(--shopee-primary);
}

/* Vận chuyển */
.shipping-info {
    align-items: flex-start;
    gap: 1rem;
}

.shipping-icon {
    color: #00bfa5;
    font-size: 1.8rem;
    margin-top: 0.2rem;
}

.shipping-free-title {
    font-size: 1.4rem;
    color: var(--text-primary);
    margin-bottom: 0.4rem;
}

.shipping-free-sub {
    font-size: 1.3rem;
    color: var(--text-secondary);
}

/* --- BÍ THUẬT: NÚT CHỌN PHÂN LOẠI HÀNG CÓ GÓC TÍCH TAM GIÁC 3D --- */
.variation-input {
    display: none;                  /* Ẩn nút radio gốc */
}

.variation-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 8rem;
    padding: 0.8rem 1.4rem;
    font-size: 1.4rem;
    color: var(--text-primary);
    background-color: var(--white-color);
    border: 1px solid rgba(0, 0, 0, 0.09);
    border-radius: 2px;
    cursor: pointer;
    position: relative;             /* Làm gốc tọa độ cho góc tam giác ::before và dấu tích ::after */
    overflow: hidden;
    user-select: none;
    transition: border-color 0.15s ease, color 0.15s ease;
}

.variation-btn:hover:not(.variation-btn--disabled) {
    border-color: var(--shopee-primary);
    color: var(--shopee-primary);
}

/* KHI NÚT PHÂN LOẠI ĐƯỢC CHỌN (:checked) -> Lên viền cam + Chữ cam */
.variation-input:checked + .variation-btn {
    border-color: var(--shopee-primary);
    color: var(--shopee-primary);
}

/* 1. Dùng ::before vẽ miếng tam giác vuông màu cam ở góc dưới-phải khi :checked */
.variation-input:checked + .variation-btn::before {
    content: "";
    position: absolute;
    right: 0;
    bottom: 0;
    border-width: 1.5rem 0 0 1.5rem; /* Tạo tam giác vuông 15x15px ở góc dưới bên phải */
    border-style: solid;
    border-color: transparent transparent transparent var(--shopee-primary);
    /* Xoay hoặc dùng clip-path để lấp đúng góc dưới bên phải */
    border: none;
    width: 1.5rem;
    height: 1.5rem;
    background-color: var(--shopee-primary);
    clip-path: polygon(100% 0, 0 100%, 100% 100%); /* Cắt tam giác vuông góc dưới-phải sắc nét tuyệt đối! */
}

/* 2. Dùng ::after in ký tự dấu tích trắng (✓) đè lên tam giác cam khi :checked */
.variation-input:checked + .variation-btn::after {
    content: "\2713";               /* Mã Unicode của dấu tích ✓ */
    position: absolute;
    right: 0.1rem;
    bottom: -0.3rem;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--white-color);
}

/* Trạng thái nút phân loại hết hàng (Disabled) */
.variation-btn--disabled {
    background-color: #fafafa;
    color: rgba(0, 0, 0, 0.26);
    border-style: dashed;
    cursor: not-allowed;
}

/* --- BỘ ĐIỀU KHIỂN SỐ LƯỢNG (QUANTITY STEPPER: [-] [1] [+]) --- */
.quantity-row {
    gap: 1.6rem;
}

.quantity-stepper {
    display: inline-flex;
    align-items: center;
}

.quantity-btn {
    width: 3.2rem;
    height: 3.2rem;
    border: 1px solid rgba(0, 0, 0, 0.09);
    background-color: var(--white-color);
    color: var(--text-secondary);
    font-size: 1.1rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Ô nhập số ở giữa: Tắt viền trái & viền phải để không bị dày gấp đôi với 2 nút +/-! */
.quantity-input {
    width: 5rem;
    height: 3.2rem;
    border-top: 1px solid rgba(0, 0, 0, 0.09);
    border-bottom: 1px solid rgba(0, 0, 0, 0.09);
    font-size: 1.5rem;
    color: var(--text-primary);
    text-align: center;
}

.stock-available {
    font-size: 1.3rem;
    color: #757575;
}

/* --- CỤM 2 NÚT HÀNH ĐỘNG CHỐT ĐƠN (DUAL CTA BUTTONS) --- */
.product-summary__actions {
    margin-top: 3rem;
    padding-left: 2rem;
    display: flex;
    align-items: center;
    gap: 1.6rem;
}

/* Nút 1: Thêm Vào Giỏ Hàng (Nền cam phấn nhạt + Viền cam + Chữ cam) */
.btn-add-to-cart {
    height: 4.8rem;                 /* Cao 48px bề thế */
    padding: 0 2.4rem;
    font-size: 1.6rem;
    background-color: rgba(238, 77, 45, 0.08);
    border: 1px solid var(--shopee-primary);
    color: var(--shopee-primary);
    gap: 1rem;
}

.btn-add-to-cart:hover {
    background-color: rgba(238, 77, 45, 0.14);
}

/* Nút 2: Mua Ngay (Nền cam đậm + Chữ trắng) */
.btn-buy-now {
    height: 4.8rem;
    min-width: 18rem;
    font-size: 1.6rem;
}

/* Dải cam kết Shopee Đảm Bảo dưới đáy */
.product-summary__guarantee {
    margin-top: 3rem;
    padding-top: 2.4rem;
    border-top: 1px solid rgba(0, 0, 0, 0.05);
    display: flex;
    align-items: center;
    gap: 3rem;
}

.guarantee-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1.35rem;
    color: var(--text-primary);
}

.guarantee-icon {
    color: var(--shopee-primary);
    font-size: 1.6rem;
}

image.png

4. Giải mã dòng code: 4 Tuyệt chiêu thực chiến tạo nên sự khác biệt ở Bài 20

  1. Vẽ góc tam giác dưới-phải bằng clip-path: polygon(100% 0, 0 100%, 100% 100%):

    • Ở Bài 17, chúng ta đã làm quen với clip-path: polygon để cắt biểu tượng QR. Hôm nay, chúng ta áp dụng nó vào .variation-btn::before với một hình vuông màu cam 15x15px nằm ở góc dưới-phải (right: 0; bottom: 0;), sau đó nối 3 đỉnh: Đỉnh trên-phải (100% 0) →\rightarrow Đỉnh dưới-trái (0 100%) →\rightarrow Đỉnh dưới-phải (100% 100%).

    • Kết hợp với dấu tích Unicode content: "\2713" ở ::after, bạn có thể click chuột trực tiếp vào từng nút Màu sắc trên trình duyệt để thấy góc tích tam giác nhảy từ nút này sang nút khác mượt mà như có JavaScript!

  2. Chia cột nhãn thuộc tính thẳng tắp bằng grid-template-columns: 11rem 1fr (.option-row):

    • Hãy nhìn vào 4 dòng: Mã Giảm Giá Của Shop, Vận Chuyển, Màu Sắc, Số Lượng. Độ dài của các chữ nhãn này rất khác nhau.

    • Thay vì dùng margin-right khiến cột nội dung bên phải bị thụt ra thụt vào lộn xộn, chúng ta cho mỗi dòng .option-row là một display: grid với cột đầu tiên khóa cứng 11rem (110px), phần còn lại 1fr. Kết quả là mọi nút Voucher, thông tin Freeship, nút Màu sắc và ô Số lượng đều thẳng hàng dọc như kẻ chỉ!

  3. Trị lỗi "Viền dày gấp đôi" ở Bộ tăng giảm số lượng (.quantity-input):

    • Trong bộ [-][ 1 ][+], hai nút - và + ở hai bên đã có đủ 4 cạnh viền border: 1px solid.

    • Vì vậy, ở ô <input class="quantity-input"> nằm kẹp ở giữa, chúng ta chỉ kẻ border-top và border-bottom, hoàn toàn bỏ trống border-left và border-right! Ba phần tử ghép lại thành một khối liền lạc với vách ngăn mỏng đúng 1px.

  4. Trạng thái nút hết hàng với border-style: dashed và cursor: not-allowed:

    • Ở lựa chọn thứ 4 (Xanh Matcha - Hết), chúng ta thêm thuộc tính disabled vào thẻ <input> và gắn class .variation-btn--disabled. Đường viền nét đứt (dashed) kết hợp biểu tượng con trỏ chuột cấm bấm (cursor: not-allowed) mang lại trải nghiệm UX chuẩn mực 100% như Shopee thật!

5. Bài tập trải nghiệm thực tế & Hẹn gặp ở Bài 21!

Hãy lưu lại file index.html và main.css, sau đó nhấn F5 trên trình duyệt để chiêm ngưỡng khu vực Chi Tiết Sản Phẩm (Chương 7) vừa ra lò:

  1. Hãy thử click chuột lần lượt vào các nút màu sắc: "Trắng Xanh", "Đen Vàng", "Tím Hồng Pastel" — bạn sẽ thấy viền cam kèm miếng tam giác có dấu tích ✓ ở góc dưới bên phải nhảy theo từng cú click của bạn!

  2. Thử rê chuột vào nút "Xanh Matcha (Hết)" để thấy con trỏ chuột biến thành biển báo cấm (not-allowed).

  3. Thử rê chuột qua 5 tấm ảnh Thumbnail nhỏ dưới chân bức ảnh lớn để thấy hiệu ứng đổi viền cam 2px sắc nét.

Thử thách khám phá dành cho bạn trước khi sang Bài 21:

  1. Bạn có thể áp dụng kỹ thuật Radio Hack (đã học ở Bài 17 và dùng cho nút Màu sắc ở trên) vào 5 tấm ảnh Thumbnail để khi bấm vào ảnh nhỏ nào thì bức ảnh lớn 450x450px ở trên tự động đổi hình theo không? Hãy thử suy nghĩ cách đặt 5 thẻ <input type="radio" name="gallery-thumb"> nhé!

  2. Hãy thử thêm dòng thuộc tính thứ 5 mang tên "Switch Phím" (với 3 nút chọn: Reaper Switch, Graywood V3, Nimbus V3) ngay bên dưới dòng Màu Sắc để luyện tập cấu trúc .option-row!

Ở Bài 21, chúng ta sẽ tiếp tục hoàn thiện phần bên dưới của Trang Chi Tiết Sản Phẩm: Xây dựng Khung Thông Tin Gian Hàng (Shop Info Bar: Avatar Shop có nhãn Yêu thích+, Nút Chat Ngay / Xem Shop và 3 cột thống kê Đánh giá, Tỷ lệ phản hồi, Tham gia) cùng Bảng Chi Tiết Thông Số Kỹ Thuật (Product Specifications)!


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.