UI Hierarchy — Elevation, Naming Convention & M3 Mapping
Dành cho: Developer muốn hiểu hệ thống phân tầng UI và quy tắc đặt tên Prerequisite: Đã đọc Stacking Design Guide Thời gian đọc: ~10 phút
1. Hệ Thống Elevation — Z-Axis
Ngoài nesting hierarchy (XY), Prisma sử dụng elevation system để quản lý các element "nổi" trên content:
Z-Index Layers
| Layer | Z-Index | Element | Ví dụ |
|---|---|---|---|
| Content | 0 |
In-flow content | Page, cards, tables |
| Sticky | 100 |
Sticky elements | Sticky header, floating action |
| Dropdown | 1000 |
Dropdown menus | Select options, context menu |
| Drawer | 1300 |
Side panels | Navigation drawer |
| Modal | 1400 |
Modal dialogs | Confirmation dialog |
| Toast | 1600 |
Notifications | Success/error messages |
| Tooltip | 1700 |
Hover hints | Help text, info popover |
Token Usage
/* Dùng z-index token, KHÔNG hardcode số */
.my-modal { z-index: var(--z-index-modal); }
.my-toast { z-index: var(--z-index-toast); }
.my-tooltip { z-index: var(--z-index-tooltip); }
.my-drawer { z-index: var(--z-index-drawer); }
Overlay Stacking Trong Stacking Design
Overlays (modal, toast, tooltip, dropdown) là Layer 5 trong process build screen:
<!-- Z-axis stacking — triggered by interaction -->
<div class="toast" style="z-index: var(--z-index-toast)">
Project created successfully!
</div>
<dialog class="modal" style="z-index: var(--z-index-modal)">
<div class="container-module layout-module-stack">
<h3>Confirm Delete</h3>
<p>Are you sure?</p>
<div class="layout-item-inline justify-end">
<button>Cancel</button>
<button class="btn-destructive">Delete</button>
</div>
</div>
</dialog>
Chú ý: Ngay cả bên trong overlay, nội dung vẫn tuân theo 4-tier nesting. Modal content = Module tier, buttons = Item tier.
2. CSS Naming Convention — 3 Elevation Layers
Prisma sử dụng elevation-based naming cho CSS classes, không phải content-based naming:
Cú Pháp
.[layer]-[component]__[element]--[modifier]
3 Layer Prefixes
| Layer | Prefix | Elevation | Background Token | Khi nào dùng |
|---|---|---|---|---|
| Ground | ground- |
level-0 | --background / --canvas |
Page body, sidebar, navbar, hero zones |
| Card | card- |
level-0~1 | --card |
Cards, lists, rows, in-flow panels |
| Surface | surface- |
level-2~5 | --surface |
Floating: toast, dropdown, modal, tooltip |
Item-level (No Prefix)
Các component nhỏ, không thuộc layer cụ thể — dùng tên trực tiếp:
.btn, .btn--primary /* Button */
.badge, .badge--success /* Badge */
.avatar /* Avatar */
.icon /* Icon */
Ví Dụ Đúng vs Sai
/* ✅ ĐÚNG — prefix cho biết layer + dùng đúng token */
.card-account { background: var(--card); color: var(--card-foreground); }
.surface-nav { background: var(--surface); color: var(--surface-foreground); }
.ground-hero { background: var(--background); }
/* ❌ SAI — tên theo data, không biết layer nào */
.balance-card { background: rgba(15, 15, 15, .7); }
.my-special-panel { background: white; }
Decision Tree — Chọn Prefix
Component nào?
│
├─ Floating (z-index > 0, backdrop-filter)?
│ └─ prefix: surface-
│ Ví dụ: surface-nav, surface-toast, surface-dropdown
│
├─ Panel / Card / Row (in-flow, elevated)?
│ └─ prefix: card-
│ Ví dụ: card-account, card-task, card-cashflow
│
├─ Page-level / Fixed bar / Background zone?
│ └─ prefix: ground-
│ Ví dụ: ground-hero, ground-header, ground-sidebar
│
└─ Small inline element (button, badge, icon)?
└─ No prefix — just component name
Ví dụ: btn, badge, avatar, icon
3. Naming Rules — 6 Quy Tắc Bắt Buộc
R1. Class prefix PHẢI phản ánh UI Layer
Background token phải match với prefix:
ground-→var(--background)/var(--canvas)card-→var(--card)surface-→var(--surface)
R2. KHÔNG đặt tên theo business data
| ❌ Sai | ✅ Đúng | Lý do |
|---|---|---|
.balance-card |
.card-account |
"balance" là data, "account" là vai trò |
.loan-section |
.card-product |
"loan" là domain, "product" là vai trò |
.user-profile-card |
.card-profile |
Bỏ "user" thừa |
R3. KHÔNG viết tắt
| ❌ Sai | ✅ Đúng |
|---|---|
.tx-item |
.item-transaction |
.btn-grp |
.button-group |
.acc-card |
.card-account |
Ngoại lệ: .btn (quá phổ biến, giữ nguyên)
R4. BEM cho children — __element, --modifier
.card-account__glass /* glass layer */
.card-account__header /* header slot */
.card-account__value /* value display */
.card-account--elevated /* variant */
.card-account--compact /* variant */
R5. Modifier cho variants, KHÔNG tạo class mới
/* ✅ ĐÚNG */
.card-task--gold { border-color: rgba(245, 196, 0, .1); }
.card-task--blue { border-color: rgba(96, 165, 250, .08); }
/* ❌ SAI */
.gold-approval-card { ... }
R6. State classes dùng suffix chuẩn
| State | Pattern | Example |
|---|---|---|
| Active | --active |
.surface-nav__tab--active |
| Disabled | --disabled |
.item-action--disabled |
| Done | --done |
.card-task--done |
| Visible | --visible |
.surface-toast--visible |
4. Prisma vs Material Design 3 — Concepts Mapping
| M3 Concept | Prisma System | Token/Class |
|---|---|---|
| Window | Block (page) | .container-block, --page-* |
| Pane | Section (region) | .container-section, --section-* |
| Surface/Card | Module (card) | .container-module, --group-* |
| Component | Item (button/input) | .container-item, --comp-* |
| Elevation | Z-index + Shadow | --z-index-*, --shadow-* |
| Canonical: List-Detail | .layout-sidebar |
Sidebar + Content |
| Canonical: Feed | .layout-{tier}-grid |
Grid layout |
| Canonical: Supporting Pane | .layout-holy-grail |
Header + Sidebar + Main |
| Show/Hide | .hide-mobile, .hide-desktop |
Responsive visibility |
| Reflow | Density mode switch | data-style-mode="compact" on mobile |
| Levitate | Modal/Drawer/Popover | Z-index elevation |
5. So Sánh Với Industry Standards
Prisma sử dụng role-based semantic naming thay vì size-based naming:
| Design System | Layout Hierarchy | Density | Gap Tokens | Approach |
|---|---|---|---|---|
| Prisma | page > section > group > comp ✅ |
4 modes ✅ | stack/inline/grid ✅ | Role-based semantic |
| Material Design 3 | small/medium/large/xl |
Component-level | ❌ | Size-based |
| Atlassian | Flat scale + components | ❌ | Via components | Numeric scale |
| Carbon (IBM) | Flat scale $spacing-01..13 |
❌ | ❌ | Numeric scale |
| Polaris (Shopify) | Flat scale --p-space-N |
❌ | Via components | Numeric scale |
| Ant Design 5.0 | Flat marginSM/MD/LG |
compactAlgorithm |
❌ | Algorithmic |
| shadcn/ui | Tailwind spacing | size variants |
Tailwind | Utility-based |
Ưu Điểm Của Prisma
| Điểm | Giải thích |
|---|---|
| Role-based semantics | Dev biết chính xác token nào dùng cho element nào, không cần đoán size |
| Density scaling tự động | Chuyển mode → toàn bộ UI scale đồng bộ |
| Radius nesting rule | Outer ≥ Inner radius được enforce tự nhiên |
| Layout patterns | stack-gap, inline-gap, grid-gap cover mọi CSS layout pattern |
| 4 cấp đủ cover | Cognitively simple — dễ nhớ, dễ dạy |
6. Code Review Checklist
Khi review code, kiểm tra:
☐ 1. Class name có prefix layer đúng? (ground-/card-/surface-/none)
☐ 2. Class name theo vai trò UI, KHÔNG theo business data?
☐ 3. Tên không viết tắt?
☐ 4. Children dùng BEM (__element, --modifier)?
☐ 5. CSS body dùng đúng bg token cho layer?
ground- → var(--background/--canvas)
card- → var(--card)
surface- → var(--surface)
☐ 6. State dùng suffix chuẩn (--active, --disabled, --done)?
☐ 7. Tier token match với element role?
Page container → --page-*
Section → --section-*
Card/Panel → --group-*
Button/Input → --comp-*