# bento-grid-checklist.md

---

# ✅ Bento Grid Pre-Ship Checklist

> Chạy qua checklist này trước mỗi lần deploy. Mục tiêu: grid đẹp, dùng được, không vỡ layout.

---

## 1. Nội dung & Hierarchy

### 1.1 Mỗi card chỉ truyền đạt đúng 1 ý duy nhất

- [ ] **Kiểm tra:** Đọc nhanh từng card trong 2 giây — nếu không hiểu ngay card đang nói gì, card đó đang cố nhét quá nhiều thông tin.

**Tại sao quan trọng:** Bento grid hoạt động dựa trên nguyên tắc *scan, không đọc*. Card có nhiều ý khiến mắt người dùng không biết dừng ở đâu, làm mất đi lợi thế visual của cả grid.

> 🔧 **Fix nhanh nếu fail:** Tách card thành 2 card nhỏ hơn, hoặc chọn 1 ý quan trọng nhất và đẩy phần còn lại xuống supporting text với font-size nhỏ hơn 20%.

---

### 1.2 Hierarchy được phân loại rõ: Primary / Secondary / Supporting

- [ ] **Kiểm tra:** Liệt kê tất cả card ra giấy và gán nhãn P (Primary), S (Secondary), Su (Supporting). Đảm bảo tỉ lệ gần đúng 1 Primary : 2–3 Secondary : còn lại là Supporting.

**Tại sao quan trọng:** Nếu mọi card đều "quan trọng như nhau", không card nào thực sự nổi bật. Hierarchy giúp mắt người dùng di chuyển có chủ đích thay vì lạc lõng trong grid.

> 🔧 **Fix nhanh nếu fail:** Chỉ định lại kích thước card theo cấp bậc — Primary dùng `col-span-2 row-span-2`, Secondary dùng `col-span-2 row-span-1`, Supporting giữ `col-span-1 row-span-1`. Điều chỉnh font-weight và màu nền tương ứng.

---

## 2. Kỹ thuật CSS

### 2.1 Gap đồng đều và padding = 1.5× gap

- [ ] **Kiểm tra:** Mở DevTools, inspect giá trị `gap` của grid container và `padding` của từng card. Công thức: `padding = gap × 1.5`. Ví dụ gap `16px` → padding phải là `24px`.

**Tại sao quan trọng:** Khoảng trắng bên trong card (padding) và khoảng cách giữa các card (gap) tạo ra nhịp thở thị giác. Nếu padding quá nhỏ so với gap, nội dung trông bị "chìm" vào viền card. Ngược lại, padding quá lớn làm không gian bên trong ngột ngạt.

> 🔧 **Fix nhanh nếu fail:** Dùng CSS custom property để đồng bộ:
> ```css
> :root { --grid-gap: 16px; }
> .bento-grid { gap: var(--grid-gap); }
> .bento-card { padding: calc(var(--grid-gap) * 1.5); }
> ```
> Thay 1 con số duy nhất là cả grid tự căn chỉnh.

---

### 2.2 `grid-row` span được reset về `auto` trên mobile

- [ ] **Kiểm tra:** Thu nhỏ viewport xuống dưới 640px. Kiểm tra không có card nào bị chiều cao cố định hoặc tạo khoảng trống bất thường do `grid-row: span N` còn sót lại từ breakpoint lớn hơn.

**Tại sao quan trọng:** Trên mobile với layout 1 cột, `grid-row: span 2` hoàn toàn vô nghĩa nhưng vẫn ảnh hưởng đến flow — card có thể chiếm chiều cao gấp đôi mà không có lý do, đẩy nội dung quan trọng xuống dưới fold.

> 🔧 **Fix nhanh nếu fail:**
> ```css
> @media (max-width: 640px) {
>   .bento-card {
>     grid-column: auto !important;
>     grid-row: auto !important;
>   }
> }
> ```
> Thêm đoạn này vào cuối stylesheet, sau tất cả rule khác.

---

### 2.3 Đã test đủ 3 breakpoint: Desktop (4 cột), Tablet (2 cột), Mobile (1 cột)

- [ ] **Kiểm tra:** Test lần lượt tại 3 viewport cụ thể: **1280px** (desktop 4 cột), **768px** (tablet 2 cột), **375px** (mobile 1 cột). Tại mỗi breakpoint, không có card nào bị overflow, text bị cắt, hoặc hình ảnh bị vỡ tỉ lệ.

**Tại sao quan trọng:** Bento grid có nhiều card với kích thước khác nhau — chỉ cần 1 card bị overflow ở tablet là cả hàng đó vỡ layout, kéo theo mọi thứ bên dưới bị lệch.

> 🔧 **Fix nhanh nếu fail:** Dùng Chrome DevTools → chọn device preset hoặc nhập width thủ công. Nếu phát hiện vỡ ở tablet, kiểm tra card nào đang dùng `min-width` cứng — thay bằng `min-width: 0` để card co được trong grid context.

---

## 3. Visual & UX

### 3.1 Card hero không chiếm quá 50% tổng diện tích grid

- [ ] **Kiểm tra:** Ước tính thủ công hoặc đo diện tích card hero (width × height) so với tổng diện tích grid. Card hero không được vượt quá 50% — lý tưởng nhất là 30–40%.

**Tại sao quan trọng:** Card hero quá lớn khiến các card còn lại trông nhỏ bé và không đáng xem, phá vỡ cảm giác "bento" — vốn hấp dẫn nhờ sự đa dạng về kích thước có kiểm soát. Ngoài ra, trên màn hình nhỏ hơn, card quá lớn chiếm hết viewport của fold đầu tiên.

> 🔧 **Fix nhanh nếu fail:** Giảm span của card hero từ `col-span-3 row-span-3` xuống `col-span-2 row-span-2`. Bù lại bằng cách tăng visual weight (màu nền đậm hơn, typography lớn hơn) thay vì tăng kích thước vật lý.

---

### 3.2 Hierarchy vẫn rõ ràng khi xem ở chế độ grayscale

- [ ] **Kiểm tra:** Trong Chrome DevTools → Rendering → Emulate vision deficiencies → chọn **"Achromatopsia"** (toàn grayscale). Nhìn vào grid và trả lời: card nào quan trọng nhất vẫn hiện ra trước không, không cần dựa vào màu sắc?

**Tại sao quan trọng:** Nếu hierarchy chỉ được tạo ra bằng màu sắc (ví dụ card hero màu xanh nổi bật, các card khác màu trắng), người dùng bị suy giảm thị giác màu sẽ không nhận ra đâu là điểm quan trọng. Đây cũng là test tốt để phát hiện hierarchy yếu ngay cả với người dùng bình thường.

> 🔧 **Fix nhanh nếu fail:** Củng cố hierarchy bằng các yếu tố không phụ thuộc màu sắc: kích thước font (`2rem` vs `1rem`), font-weight (`700` vs `400`), kích thước card, và mật độ whitespace bên trong card.

---

### 3.3 Mỗi card có hover state với feedback thị giác nhẹ

- [ ] **Kiểm tra:** Hover chuột lên từng card trên desktop. Phải có ít nhất 1 trong các phản hồi sau: scale nhẹ (`scale(1.02)`), shadow xuất hiện/đậm hơn, border đổi màu, hoặc background shift tinh tế. Transition phải mượt, duration trong khoảng `150ms–250ms`.

**Tại sao quan trọng:** Hover state xác nhận với người dùng rằng card này *có thể tương tác được* — đặc biệt quan trọng nếu card là link hoặc button. Thiếu feedback khiến grid trông tĩnh và "chết", đồng thời tăng tỉ lệ người dùng không nhận ra card là clickable.

> 🔧 **Fix nhanh nếu fail:**
> ```css
> .bento-card {
>   transition: transform 200ms ease, box-shadow 200ms ease;
> }
> .bento-card:hover {
>   transform: scale(1.02);
>   box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
> }
> ```
> Không dùng `transition: all` — chỉ transition đúng property cần thiết để tránh performance hit.

---

> **Ghi chú:** Checklist này áp dụng cho bento grid dạng marketing/landing page. Nếu dùng cho dashboard hoặc data-heavy layout, cân nhắc bỏ qua mục 3.1 và điều chỉnh mục 1.2 theo context cụ thể.