Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> CSS

Cách tạo Responsive Column Cards (Card cột responsive) với CSS

Giới thiệu

Column Cards là pattern UI phổ biến để hiển thị danh sách sản phẩm, dịch vụ, bài viết, team members... Yêu cầu: cùng chiều cao, responsive (4 cột → 2 cột → 1 cột), nội dung canh giữa.

Ví dụ hiện đại: CSS Grid + Auto-fit (Khuyến nghị)

<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Responsive Column Cards</title>
    <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; background: #f5f5f5; padding: 2rem; }
        
        .cardsContainer {
            max-width: 1200px; margin: 0 auto;
            display: grid;
            /* Tự động tạo cột: tối thiểu 250px, tối đa 1fr, fill khoảng trống */
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 24px;
        }
        
        .card {
            background: white;
            border-radius: 16px;
            padding: 2rem;
            text-align: center;
            box-shadow: 0 4px 12px rgba(0,0,0,0.08);
            transition: transform 0.3s, box-shadow 0.3s;
            display: flex; flex-direction: column; align-items: center;
        }
        .card:hover {
            transform: translateY(-6px);
            box-shadow: 0 16px 32px rgba(0,0,0,0.12);
        }
        
        .cardIcon {
            width: 72px; height: 72px; border-radius: 50%;
            display: flex; align-items: center; justify-content: center;
            margin-bottom: 1rem; font-size: 1.8rem; color: white;
        }
        .card h3 { font-size: 1.3rem; color: #2c3e50; margin-bottom: 0.5rem; }
        .card p { color: #666; font-size: 1rem; line-height: 1.6; }
        
        /* Màu sắc riêng cho từng card */
        .card:nth-child(1) .cardIcon { background: linear-gradient(135deg, #991dd0, #c01ed0); }
        .card:nth-child(2) .cardIcon { background: linear-gradient(135deg, #0c7e78, #0f9d96); }
        .card:nth-child(3) .cardIcon { background: linear-gradient(135deg, #cf295b, #e03a6b); }
        .card:nth-child(4) .cardIcon { background: linear-gradient(135deg, #cc5b27, #e07030); }
    </style>
</head>
<body>
    <h1 style="text-align:center; margin-bottom:0.5rem; color:#2c3e50;">Responsive Column Cards</h1>
    <p style="text-align:center; color:#666; margin-bottom:2rem;">Resize màn hình để thấy card tự điều chỉnh cột</p>
    
    <div class="cardsContainer">
        <div class="card">
            <div class="cardIcon"><svg xmlns="https://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></div>
            <h3>Thẻ đầu tiên</h3>
            <p>Mô tả ngắn gọn về tính năng hoặc dịch vụ này. Nội dung hấp dẫn người dùng.</p>
        </div>
        <div class="card">
            <div class="cardIcon"><svg xmlns="https://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
            <h3>Thẻ thứ hai</h3>
            <p>Mô tả ngắn gọn về tính năng hoặc dịch vụ này. Nội dung hấp dẫn người dùng.</p>
        </div>
        <div class="card">
            <div class="cardIcon"><svg xmlns="https://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="16"/></svg></div>
            <h3>Thẻ thứ ba</h3>
            <p>Mô tả ngắn gọn về tính năng hoặc dịch vụ này. Nội dung hấp dẫn người dùng.</p>
        </div>
        <div class="card">
            <div class="cardIcon"><svg xmlns="https://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></div>
            <h3>Thẻ thứ tư</h3>
            <p>Mô tả ngắn gọn về tính năng hoặc dịch vụ này. Nội dung hấp dẫn người dùng.</p>
        </div>
    </div>
</body>
</html>

Phân tích: repeat(auto-fit, minmax(250px, 1fr))

Đây là "holy grail" của responsive grid - không cần media query:

  • auto-fit: Tự động tính số cột vừa khung chứa.
  • minmax(250px, 1fr): Cột tối thiểu 250px, tối đa chia đều không gian còn lại.
  • Kết quả: >1000px → 4 cột; 768-1000px → 3 cột; 500-768px → 2 cột; <500px → 1 cột.

So sánh với code gốc (Float + calc)

Tiêu chí Float + calc() (Gốc) Grid auto-fit (Hiện đại)
Media queriesCần (600px breakpoint)Không cần
Số cột linh hoạtCố định 4 → 1Tự động 4→3→2→1
Equal heightCần height cố định / flex hackTự động (align-items: stretch)
GapMargin phức tạpgap: 24px đơn giản
Code lines~25 dòng CSS~10 dòng CSS

Biến thể: Card với nội dung không đều (Equal height cards)

Grid tự động làm cho các card trong cùng hàng có chiều cao bằng nhau. Nội dung ngắn sẽ có khoảng trống dưới, nội dung dài sẽ đẩy card cao hơn - các card khác cùng hàng sẽ co giãn theo (nhờ align-items: stretch mặc định).

Để nội dung luôn đẹp: Dùng display: flex; flex-direction: column trên .card, cho .card p có flex: 1 (chiếm phần còn lại), nút CTA luôn ở dưới cùng.

.card {
    display: flex; flex-direction: column;
}
.card p { flex: 1; }
.card .btn { margin-top: auto; } /* Luôn đẩy xuống dưới */