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

Pro­duct
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áiTriggerVisual
StackedMặc định / scroll lên5 card xếp chồng, xoay ±14°
FannedScroll xuống / swipe upCard xòe ra theo cung tròn R≈70vw
HoveredDi chuột vào cardCard đượ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 đó:

  1. Clone card-box (phần bên trong, không bị rotate) thành position: fixed
  2. Phase 1 (0–700ms): card bay về center màn hình
  3. Phase 2 (700ms): snap về center, scale up phủ màn hình, text mờ dần
  4. Phase 3 (1220ms): card fade out
  5. 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.