Card Hierarchy Padding — Phân Tích (v2)
Trigger: Dashboard showcase — Card Large và Card Small đều dùng padding 24px → small card bị "phình" Status: 🔍 ANALYZED → ⚡ CORRECTED Related: material-design-3-layout.md, default.tokens.json
1. Phản biện ban đầu
❌ Hướng sai: Padding khác nhau theo card size cùng cấp
Phân tích v1 đề xuất: stat card (nhỏ) → padding-small, chart card (lớn) → padding-default.
Vấn đề: Cùng nằm trên 1 grid, cùng cấp layout → padding khác nhau gây lệch visual alignment.
❌ WRONG: cùng cấp, padding khác nhau
┌─ grid ──────────────────────────────────────────┐
│ ┌─ 16px ─┐ ┌─ 16px ─┐ ┌─ 16px ─┐ ┌─ 16px ─┐ │
│ │ stat │ │ stat │ │ stat │ │ stat │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
│ ┌──── 24px ───────────────┐ ┌──── 24px ─────┐ │
│ │ chart │ │ donut │ │
│ └─────────────────────────┘ └───────────────┘ │
│ ↑ lệch vì padding khác cấp trên cùng grid! │
└─────────────────────────────────────────────────┘
✅ ĐÚNG: Padding thay đổi khi khác cấp nesting (card-in-card)
✅ CORRECT: same level = same padding, nesting = smaller padding
┌─ ground-content (block padding: 32px) ──────────────────┐
│ │
│ ┌─ card L1 (group-padding-default: 24px) ───────────┐ │
│ │ │ │
│ │ Content trực tiếp trên card này: 24px padding │ │
│ │ │ │
│ │ ┌─ card L2 (group-padding-small: 16px) ────────┐ │ │
│ │ │ │ │ │
│ │ │ Card nested bên trong → giảm padding │ │ │
│ │ │ │ │ │
│ │ │ ┌─ card L3 (comp-padding: var(--spacing-3)) ───────────┐ │ │ │
│ │ │ │ Second nesting → comp tier │ │ │ │
│ │ │ └───────────────────────────────────────────┘ │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
2. Quy Tắc: Nesting-Based Padding
2.1 Nguyên tắc cốt lõi
Cùng cấp layout → cùng padding. Khác cấp nesting → giảm padding theo tier.
| Nesting Level | Tier | Padding Token | Value | Ví dụ |
|---|---|---|---|---|
| L0 — Page shell | Block | --page-padding-default |
24px | ground-content |
| L1 — Card trực tiếp trên page | Module | --group-padding-default |
24px | stat, chart, table, activity |
| L2 — Card trong card | Module (small) | --group-padding-small |
16px | Section bên trong card |
| L3 — Card trong card trong card | Item | --comp-padding-default |
12px | Widget in nested card |
2.2 Cùng cấp = đồng nhất
Mọi card L1 trên dashboard grid phải dùng cùng padding bất kể card lớn hay nhỏ:
/* TẤT CẢ card L1 — cùng padding */
.card-stat,
.card-chart,
.card-table,
.card-activity {
padding: var(--group-padding-default); /* 24px — tất cả cùng cấp */
}
2.3 Khi nào giảm padding?
Chỉ giảm khi card nằm trong card (nesting):
/* Card nested bên trong card khác */
.card-chart .card-inner,
.card-table .card-nested-widget {
padding: var(--group-padding-small); /* 16px — giảm 1 bậc */
}
3. Quay lại bài toán Dashboard
Stat card padding 24px có thật sự "to" không?
Nếu tuân thủ quy tắc cùng cấp = cùng padding → 24px là đúng. Cảm giác "to" có thể do:
| Nguyên nhân thực | Giải pháp đúng |
|---|---|
| Card stat quá hẹp (4/row) → tỷ lệ padding/content cao | Giảm grid columns (3/row) hoặc giảm gap |
| Content bên trong stat card quá ít | Thêm sparkline, progress bar, hoặc sub-metric |
| Font size quá nhỏ so với padding | Tăng font size để content "fill" card hơn |
→ Không nên giải quyết bằng cách giảm padding — phá vỡ visual alignment.
4. Cross-Reference: MD3 & Apple HIG
Material Design 3
- Tất cả card cùng surface level → cùng padding (16dp default)
- Nested containers → padding giảm theo depth
- Không phân biệt padding theo card size — chỉ theo nesting depth
Apple HIG
- Widget padding scale theo widget zone, không theo kích thước riêng
- Small/Medium/Large widget → khác padding vì khác context (home screen zone), không phải vì size
Nguyên tắc chung
Spatial consistency > content-proportional padding. Visual grid alignment quan trọng hơn tỷ lệ padding/content riêng lẻ.
5. Kết Luận (Updated)
| # | Finding | Action |
|---|---|---|
| 1 | Cùng cấp layout phải cùng padding | ✅ Rule: L1 cards = --group-padding-default |
| 2 | Padding chỉ giảm khi nesting (card-in-card) | ✅ Rule: L2 = --group-padding-small |
| 3 | Stat card "phình" không phải do padding sai | 🔍 Do content density hoặc grid ratio |
| 4 | v1 đề xuất sai vì gây lệch visual | ❌ Reverted |
[!TIP]
Dashboard hiện tại chưa có card-in-card nên chưa cầnpadding-small. Nếu muốn stat card "gọn" hơn, giải pháp đúng là tăng content density hoặc điều chỉnh grid layout, không phải giảm padding.