Radial Menus & Nonlinear UX: Hướng dẫn xây dựng experimental navigation cho web 2026

6 tháng trước · 12 phút đọc
Navigation web đang chán như hamburger menu từ 2012
Bạn có nhận ra không? Gần như mọi web đều giống nhau: logo góc trái, hamburger icon góc phải, dropdown trắng phẳng. Safe. Predictable. Nhàm.
Năm 2026, một luồng gió khác đang nổi lên - experimental navigation: radial menus tỏa ra như tia sáng, hidden drawers ẩn mình chờ gesture, và nonlinear journeys biến người dùng từ passive scroller thành người khám phá chủ động. Không phải trend thẩm mỹ thuần túy - đây là sự thay đổi về tư duy UX.
Navigation truyền thống vs experimental - khác nhau ngay ở cách người dùng cảm nhận hành trình
Bài này mình sẽ đi vào 3 phần cụ thể: tại sao trend này xuất hiện, cách build radial menu bằng CSS/JS thuần, và cách tích hợp Locomotive Scroll để tạo nonlinear UX thực sự. Có code chạy được, có case study, và có cả những trade-off mà nhiều tutorial khác bỏ qua.
Tại sao radial menu và nonlinear UX lại nổi lên năm 2026
Có 2 lý do kỹ thuật đẩy trend này lên.
Thứ nhất, trình duyệt đã đủ mạnh. View Transitions API hiện đạt over 85% of browsers (dev.to - Smooth Page Transitions with Zero Libraries: The View Transitions API) độ phủ trình duyệt, CSS Anchor Positioning đã stable trên Chrome, Firefox, và Safari. Những API này làm cho smooth state transitions giữa các "không gian" trong trang trở nên khả thi mà không cần thư viện nặng.
Thứ hai, người dùng đã quen với spatial interaction - từ mobile app (swipe, pinch, long-press radial) đến game UI. Não họ đã được train để explore không gian thay vì follow list.
Các API hiện đại là nền tảng cho experimental nav - đừng build trên nền cát
Nhưng quan trọng hơn là context sử dụng. Radial menu và nonlinear UX không phải cho tất cả mọi web. Nó phù hợp khi:
- Portfolio/creative agency: Người dùng đến để bị impressed, không phải để checkout nhanh
- Storytelling/editorial: Nội dung có nhiều luồng tường thuật, không tuyến tính
- Product discovery: Khám phá catalog sản phẩm như đi chợ, không phải tìm theo SKU
E-commerce checkout? Booking form? Banking app? Giữ linear. Mình nhấn mạnh điều này vì có khá nhiều dev apply trend lên sai context, rồi conversion rate rơi tự do.
Build radial menu từ đầu với CSS và JavaScript thuần
Mình sẽ bỏ qua phần lý thuyết và đi thẳng vào code.
Ý tưởng cốt lõi: Một nút trigger cố định, khi click sẽ fan các menu items ra theo góc tính bằng Math.atan2(). Không cần thư viện - chỉ cần CSS transform và 20 dòng JS.
Phần HTML
Phần CSS
Phần JavaScript - logic tính góc
Logic tính góc: Math.cos(angle) cho X, Math.sin(angle) cho Y - đây là trái tim của radial menu
Mình dùng cubic-bezier(0.34, 1.56, 0.64, 1) vì nó tạo bounce nhẹ khi item bay ra - cảm giác "sống động" hơn ease-out thẳng. Nếu cần accessible hơn, thêm @media (prefers-reduced-motion: reduce) để fallback về transition 0s.
Tải bản demo đầy đủ (HTML/CSS/JS trong 1 file) tại đây: Tải demo radial menu (HTML)
Nonlinear UX với Locomotive Scroll: từ prototype đến production
Radial menu chỉ là một mảnh. Phần khó hơn là tạo ra một nonlinear journey thực sự - nơi người dùng cảm giác đang explore không gian, không phải scroll trang.
Locomotive Scroll v4+ là lựa chọn phổ biến nhất cho việc này. Điểm mạnh của nó không phải smooth scroll (bây giờ CSS scroll-behavior: smooth đã đủ tốt), mà là scroll spy - khả năng fire events theo vị trí scroll để trigger các state thay đổi.
Setup cơ bản
Locomotive Scroll làm trung gian: scroll events kích hoạt radial menu đúng thời điểm người dùng cần
Nonlinear journey pattern cho app Việt
Mình đã prototype một flow này cho một creative agency nhỏ ở Hà Nội. Vấn đề họ gặp: portfolio của họ có 6 loại dự án khác nhau (brand, motion, UI, print...), nhưng nếu list theo dropdown thì mất đi cảm giác sáng tạo.
Solution: Trang chủ là một "map" dạng scroll ngang, mỗi section là một "vùng" dự án. Radial menu hiện khi user scroll vào vùng đó, với các items thay đổi theo context:
Kết quả: người dùng không cần quay lại nav bar. Menu luôn relevant với nội dung đang xem. Đây là điểm mấu chốt của contextual navigation - một phần quan trọng của nonlinear UX.
Trade-offs mà bạn cần biết trước khi ship production
Mình không muốn bài này chỉ là tutorial màu hồng. Đây là những vấn đề thực tế.
Mobile touch precision là thách thức lớn nhất. Radial menu trên desktop hoạt động mượt vì bạn có chuột chính xác đến pixel. Trên mobile, ngón tay có diện tích tiếp xúc lớn hơn và người dùng không biết chính xác họ đang chạm vào đâu trong không gian radial. Minimum touch target 44px là baseline, nhưng khi 6 items tỏa ra trong 270 độ với radius 90px, tổng chu vi là ~424px - chỉ còn ~70px mỗi item. Ổn với 4 items, chật chội với 6+.
Solution thực tế: Giảm số items xuống còn 4 tối đa trên mobile, hoặc switch sang bottom sheet khi detect touch device:
Desktop vs mobile - đừng force một pattern cho cả hai, adaptive là đúng hướng
Accessibility cũng không đơn giản. Radial menu cần keyboard navigation (Tab/Arrow keys), focus visible rõ ràng, và screen reader labels. Đây là phần tốn thời gian nhất:
Performance với Locomotive Scroll: thư viện này dùng requestAnimationFrame loop và clone DOM để tính scroll position. Trên device thấp (phần lớn người dùng VN vẫn dùng thiết bị tầm trung), lerp animation có thể jank. Test kỹ trên Pixel 6a hoặc thiết bị tương đương trước khi ship.
Và cuối cùng - đừng quên fallback graceful. Nếu JS fail, user vẫn cần navigate được. CSS-only fallback hay server-side rendered nav luôn cần có sẵn.
Prototype trong Figma trước khi viết một dòng code
Có một bước mà nhiều dev hay bỏ qua: validate pattern trước khi build. Radial menu trông cool trên Dribbble nhưng user có hiểu cách dùng không?
Figma 2025-2026 có vài tính năng hỗ trợ tốt cho experimental nav prototyping:
Smart Animate + Component States: Tạo component radial menu với 2 states (closed/open), dùng Smart Animate để preview animation fan-out thực tế. Không cần code, khách hàng click được ngay.
FigJam cho journey mapping: Vẽ nonlinear user journey trên FigJam - các vùng nội dung như nodes, user paths như edges. Giúp team thống nhất flow trước khi design chi tiết.
Dev Mode export: Khi đã approved, Dev Mode generate CSS variables và spacing tokens tự động. Với radial layout, bạn có thể export exact border-radius, box-shadow, và timing functions cho transition.
Figma prototype giúp validate trước khi code - tiết kiệm nhiều ngày debug
Một tip nhỏ: Dùng Figma Make (AI prototyping tool) để generate interactive prototype từ mô tả text. Prompt kiểu "Radial menu 4 items, trigger button góc dưới phải, fan-out khi click, smooth animation" sẽ cho ra prototype click-through nhanh hơn tự build.
Sau đó test với ít nhất 5 người dùng thật. Câu hỏi cần trả lời: Họ có discover được menu không? Họ hiểu các items sẽ làm gì không trước khi click? Nếu câu trả lời là "không" cho 3/5 người - reconsider.
Nếu bạn chưa quen với CSS animation và muốn build solid foundation trước khi nhảy vào experimental UI, khóa HTML CSS Pro có phần animation và transform khá chi tiết, là nền tốt để hiểu mechanism đằng sau những gì mình code ở trên.
Từ experimental đến production: checklist trước khi ship
Bạn đã có prototype approved, đã viết code, đã test basic. Trước khi deploy, check những điểm này.
Tải checklist đầy đủ: Tải checklist production radial menu
Performance audit:
- [ ] Lighthouse Performance score > 85 trên mobile (throttle 4G)
- [ ] Radial animation dùng
transformvàopacityonly - KHÔNG animatetop/left/width/height - [ ] Locomotive Scroll
lerpvalue ≤ 0.1 trên thiết bị low-end - [ ]
will-change: transformchỉ set khi element sắp animate, remove sau khi xong
Accessibility audit:
- [ ] Keyboard navigation hoàn chỉnh (Tab, Arrow keys, Enter, Escape)
- [ ]
role="menu"vàrole="menuitem"đúng chỗ - [ ]
aria-expandedtrên trigger phản ánh đúng state - [ ] Test với VoiceOver (Mac) hoặc NVDA (Windows)
- [ ]
@media (prefers-reduced-motion: reduce)disable animation
Mobile/touch audit:
- [ ] Touch target tối thiểu 44×44px cho mỗi item
- [ ] Test trên Chrome DevTools với touch emulation
- [ ] Fallback navigation accessible khi JS fail hoặc trên touch-only device
Checklist không phải formality - mỗi item là một bug đã từng xảy ra ở production
Browser compat:
- [ ]
document.startViewTransitioncó fallback graceful - [ ] CSS Anchor Positioning có fallback
position: fixed - [ ] Test Safari iOS - vẫn còn quirks với
position: fixedtrong scroll containers
Experimental navigation không đồng nghĩa với "skip những thứ boring như accessibility". Ngược lại - khi UX pattern đã unconventional, accessibility lại càng phải solid hơn bình thường, bởi vì người dùng không có mental model sẵn để fallback.
Bước tiếp:
- Clone demo radial menu ở trên, mở trong browser
- Chạy Lighthouse audit ngay trên localhost
- Test keyboard navigation - bạn có navigate được mà không dùng chuột không?
- Nếu pass cả 3, bạn đã sẵn sàng integrate vào project thật
Gặp vướng mắc với animation timing hay Locomotive config, drop comment - mình sẽ reply.
