Fan Cards
Fan Cards là một navigation pattern lấy cảm hứng từ cách cầm bài — khi chưa cần dùng, các lá bài xếp chồng gọn gàng; khi muốn chọn, tay xòe ra và mỗi lá hiện rõ.
Trên web, behavior này được trigger bằng scroll: idle = stacked, scroll xuống = fanned, scroll lên = collapse.
About
Product
Design
Product designer
#prototype
Exclusion
Tabs
Filter pattern
Journal
Growth
Notes
Daily discoveries
Playbook
Know
how
UX Playbook
Now
On my
Mind
On my mind
Tại sao dùng pattern này
Navigation truyền thống hiển thị tất cả các mục cùng lúc. Fan Cards chọn hướng ngược lại: ẩn trước, tiết lộ sau. Điều này có một vài lợi ích:
- Màn hình sạch hơn khi idle — người dùng nhìn vào trang chủ không bị quá tải bởi menu
- Scroll = gesture chủ động — người dùng cần làm gì đó có chủ đích để reveal navigation, không bị phân tâm ngẫu nhiên
- Ẩn dụ vật lý — chuyển động xòe bài rất tự nhiên, không cần label “Click để xem menu”
Các trạng thái
| Trạng thái | Trigger | Visual |
|---|---|---|
| Stacked | Mặc định / scroll lên | 5 card xếp chồng, xoay ±14° |
| Fanned | Scroll xuống / swipe up | Card xòe ra theo cung tròn R≈70vw |
| Hovered | Di chuột vào card | Card được hover nổi lên 2vw |
Hover flicker fix
Khi card fanned di chuyển lên theo hover, cursor có thể thoát ra ngoài ranh giới card — gây vòng lặp flicker. Giải pháp: mở rộng hit area xuống dưới bằng ::after pseudo-element, kết hợp debounce 120ms trước khi remove class .hovered.
Page transition
Khi click vào một card, không navigate ngay. Thay vào đó:
- Clone
card-box(phần bên trong, không bị rotate) thànhposition: fixed - Phase 1 (0–700ms): card bay về center màn hình
- Phase 2 (700ms): snap về center, scale up phủ màn hình, text mờ dần
- Phase 3 (1220ms): card fade out
- Navigate (1520ms)
Lý do clone card-box thay vì fan-card: card-1 bị rotate -25°, nên getBoundingClientRect() của nó trả về bounding box lớn hơn thực tế — tính toán center bị lệch. card-box bên trong không bị rotate nên rect chính xác.