Navigation ứng dụng di động phải gói toàn bộ kiến trúc thông tin vào màn 360-414px portrait, dưới ngón cái với 1-2 tap. Bài này giải thích 5 pattern (bottom tab, hamburger drawer, top tab, FAB, stack), khi nào dùng pattern nào, kết hợp dual nav, accessibility WCAG 2.2 và 7 lỗi thường gặp khi audit navigation mobile.
Bottom Tab Bar — pattern mặc định 2026 cho app 3-5 mục chính
Bottom Tab Bar là dải navigation cố định ở đáy màn chứa 3-5 icon + label, mỗi icon là 1 destination chính. Đây là pattern thấy ở Instagram, Twitter, YouTube, Spotify, Shopee, Lazada, Tiki, MoMo, ZaloPay — gần như mọi app top trên App Store / Google Play 2026.
Lý do dominant: gần ngón cái (thumb zone), 1 tap đến destination, luôn visible nhắc nhở user còn destination khác. Conversion bottom tab cao hơn hamburger 20-40% theo đo Nielsen Norman trên 50+ mobile e-commerce app 2024.
Cấu hình chuẩn và variant Material/iOS
Cấu hình chuẩn: 3-5 mục (3 nếu app đơn giản, 5 nếu app rộng — quá 5 buộc dùng “More” overflow hoặc chuyển pattern khác). Mỗi mục có icon 24×24px + label tiếng Việt 1-2 từ (Trang chủ, Giỏ, Tài khoản, Khám phá, Đơn hàng).
Mục active có color contrast cao (thường primary color), inactive là gray 60% opacity. Tap area mỗi tab >= 44×44px — chiều rộng = viewport width / số tab, chiều cao 56-64px bao gồm safe-area-inset-bottom cho iPhone notch.
Material vs iOS — đặt tên neutral
Material Design 3 phân biệt 2 biến thể. Navigation Bar (mục đích như tab bar nhưng có pill-shape highlight cho active state, label luôn visible).
Navigation Rail (vertical bar bên trái, cho tablet landscape >= 600dp).
Apple HIG gọi là Tab Bar, Material gọi Navigation Bar — cùng concept. Khi build cross-platform với component library, đặt tên neutral như BottomNav hoặc TabBar tránh confusion team.
Implement React và animation
Dùng position: fixed; bottom: 0; left: 0; right: 0; hoặc position: sticky. Padding-bottom container chính += env(safe-area-inset-bottom) để content không bị che bởi tab.
Animation chuyển tab smooth 200-300ms với easing cubic-bezier(0.4, 0, 0.2, 1).
Lazy-load content tab inactive để giảm initial bundle. Library hỗ trợ: React Navigation (React Native), Radix UI Tabs hoặc Headless UI cho web app, shadcn/ui BottomNavigation.
Test trên iPhone SE 375px width đảm bảo 5 tab không bị crush quá nhỏ.
Khi nào KHÔNG dùng bottom tab bar
Bottom tab không phù hợp 3 ngữ cảnh sau. App có nhiều destination ngang hàng cần drawer hoặc full-screen nav, app đọc content dài nên giải phóng full screen.
- App > 5 destination chính: Gmail có Inbox/Starred/Sent/Drafts/Spam/Trash/Important = 7 mục — drawer hợp lý hơn.
- App đọc content dài: ebook reader, PDF viewer, longform reader — bottom tab che mất 56-64px content quý.
- Landing hero full-screen: full-screen video, hero chiến dịch — không nên có bottom tab che 56-64px dưới.
Hamburger Drawer — ẩn nav ưu tiên content area
Hamburger Drawer ẩn navigation sau icon ☰ ở top-left, slide ra từ trái khi tap. Pattern dominant 2014-2018, sau đó bị NN/g chỉ trích vì giảm discoverability — user không biết app có feature gì cho đến khi mở drawer.
2026 vẫn dùng nhưng chỉ trong ngữ cảnh phù hợp — app nhiều mục 10+, hoặc khi mục main đã quen thuộc user (Gmail, Slack, Discord). User mở app đã biết có Settings ở đâu, không cần discoverability cao.
Cấu hình drawer chuẩn
Width 280-320px (75-85% viewport phone). Backdrop dim 50% opacity bên ngoài.
Tap backdrop hoặc swipe trái để đóng. Animation slide-in 250ms easing decelerate cubic-bezier(0.0, 0.0, 0.2, 1).
Header drawer có avatar + tên user + email + badge plan. Body list 8-15 mục với icon + label, separator giữa group.
Footer drawer có Settings, Help, Logout — cố định ở bottom drawer, không scroll mất.
3 biến thể drawer
- Standard drawer: overlay lên content, mobile mặc định. Slide từ trái, backdrop dim.
- Persistent drawer: push content sang phải, chỉ tablet >= 600dp. Coexist không overlay.
- Mini drawer: chỉ hiện icon, hover/tap mở rộng. Pattern hợp desktop hoặc tablet landscape, không phù hợp phone vì không hover.
Implement và accessibility
Dùng <dialog> element native (browser support tốt 2024+) hoặc Radix UI Dialog primitive. Trap focus khi mở — Tab key chỉ chạy trong drawer.
Restore focus về hamburger button khi đóng — quan trọng cho keyboard navigation.
ARIA: drawer có role="navigation" + aria-label="Main menu". Hamburger button có aria-expanded binding state đóng/mở.
Test với VoiceOver iOS và TalkBack Android xác minh screen reader announce đúng.
Anti-pattern khi triển khai drawer
Nhồi 20+ mục vào drawer thành nested menu 3 cấp — user phải tap 3-4 lần để đến destination. Tỉ lệ task completion drop 40-60% so flat menu.
Đúng cách: nếu > 15 mục, gộp vào groups + collapse/expand theo group, hoặc tách dual navigation (bottom tab cho 5 main + drawer cho settings phụ). Hierarchy thị giác rõ giúp user scan drawer nhanh hơn.
Top Tab Scrollable — nhiều section ngang hàng
Top Tab Scrollable là hàng tab ngang ở dưới app bar cho phép swipe horizontal hoặc tap chuyển giữa section nội dung cùng cấp. Pattern thấy ở Gmail (Primary, Promotions, Social, Updates), TikTok For You/Following, Twitter Home/For You, Discord channel tabs.
Ưu điểm: chứa được 5-15 section mà không cần drawer, swipe gesture tự nhiên trên mobile. Hợp với app có 2 trục thông tin — trục dọc (destination) và trục ngang (filter trong destination).
Cấu hình top tab
Tab height 40-48px. Label only hoặc icon+label tuỳ space.
Active tab có underline 2-3px hoặc background pill. Scroll horizontal khi tab tổng width > viewport.
Khi tap tab cuối visible, scroll-snap để hiện tab tiếp theo. Indicator slide animation khi swipe content (linked với scroll position) — chi tiết mịn quan trọng tạo cảm giác native không phải web junk.
Kết hợp với bottom tab
Top Tab thường kết hợp với Bottom Tab. Bottom = destination chính, top = filter trong destination đó.
Gmail bottom có Mail/Meet, top có Primary/Promotions/Social. TikTok bottom có Home/Discover/Inbox/Profile, top có For You/Following.
Pattern dual navigation phục vụ app có 2 trục thông tin. Tránh dùng nếu app chỉ có 1 trục — over-engineering, user confused giữa 2 tier nav cùng look-feel.
Implement và ARIA
Dùng react-tabs, @radix-ui/react-tabs, hoặc framer-motion cho animation swipe. Library swipeable-views (legacy) hoặc embla-carousel (modern, lightweight) cho swipe gesture.
Lazy-load content tab inactive.
ARIA: role="tablist" trên container, role="tab" + aria-selected trên mỗi tab, role="tabpanel" + aria-labelledby cho content. Keyboard: Left/Right arrow chuyển tab, Tab key focus vào content.
FAB Floating Action Button — action chính nổi bật
FAB là button tròn nổi (thường 56×56dp, đôi khi extended với label) đặt floating ở góc dưới-phải hoặc giữa-dưới, đại diện cho action chính của screen. Pattern Material Design đặc trưng — Gmail Compose, Google Maps “+ điểm đến”, Twitter Compose.
iOS HIG không có FAB chính thức nhưng nhiều app iOS dùng (Twitter, Pinterest, Asana). Hợp khi action chính chiếm 50-70% use case của screen.
Ngược lại trên Settings không có FAB vì không có 1 action chính nổi bật.
3 size FAB chuẩn
- Standard FAB 56×56dp: icon 24×24dp ở giữa, elevation shadow 6dp default + 12dp khi pressed. Default cho hầu hết app.
- Mini FAB 40×40dp: cho space hẹp, secondary action. Ít dùng — nếu cần mini thì xem lại có nên dùng FAB không.
- Extended FAB: chiều cao 48dp + label text bên cạnh icon (vd “+ Compose”). Dùng khi muốn nhấn mạnh action với label rõ ràng.
Position bottom-right vs center
Material chuẩn bottom-right 16dp margin từ edge. Center-bottom dùng khi FAB là action quan trọng nhất + bị bottom tab “đè” lên (Facebook camera button giữa).
Right-handed user 85-90% global → bottom-right tự nhiên hơn cầm phone tay phải. Lefty user có thể setting flip nhưng đa số app không hỗ trợ — chấp nhận trade-off này 2026.
FAB + Bottom Tab kết hợp
FAB có thể kết hợp với Bottom Tab — FAB ở giữa bar (bị “đè” lên bar, có notch effect như Apple Pay button). Pattern thấy ở app delivery (Grab, Gojek) với FAB là search location, hoặc social (Facebook camera button giữa).
Kỹ thuật: bar có SVG path với cutout tròn ở giữa, FAB position absolute lên trên cutout. Cẩn thận giữ touch target không lẫn giữa FAB và 2 tab bên cạnh — spacing 8dp minimum.
Anti-pattern FAB phổ biến
FAB cho action không phải primary (vd FAB cho Settings — sai vì Settings không phải action thường xuyên). FAB block content (đặt trên content quan trọng cần scroll qua).
FAB di chuyển position khi scroll (gây disorientation).
Đúng cách: FAB chỉ cho 1 action chính rõ ràng, position cố định, có animation hide-on-scroll-down + show-on-scroll-up nếu content dài. Hide gradient 100-200ms, show 200-300ms.
Stack Navigation — push/pop screen flow
Stack Navigation là pattern push màn hình mới lên stack khi user vào sâu hơn, pop ra khi back. App bar có nút back (←) ở top-left tự động, screen có thể có CTA sticky bottom.
Đây không phải menu navigation mà là cấu trúc flow giữa screen.
Apple HIG gọi là Navigation Bar, Material gọi Top App Bar. Stack thường layer trên top của Bottom Tab hoặc Drawer — user ở tab “Khám phá” → tap product → push ProductDetail → tap “Đánh giá” → push ReviewList → tap user → push UserProfile.
Cấu hình app bar
Chiều cao 56dp Android / 44pt iOS (không tính status bar). Title center hoặc left tuỳ design language.
Back button left auto khi có previous screen trong stack. Action button right (Search, Filter, More).
Title nên ngắn <= 25 ký tự để không bị truncate. Animation transition push/pop: slide horizontal 300ms (iOS chuẩn) hoặc fade + scale (Material).
Bỏ animation hoàn toàn khiến app feel “web-like” thay vì native.
Sticky CTA bottom trên stack screen
Sticky CTA thường đi cùng stack screen. ProductDetail có “Thêm vào giỏ” + “Mua ngay” sticky bottom.
CheckoutSummary có “Đặt hàng”. Article có “Đăng ký nhận bài”.
CTA này khác bottom tab bar — context-specific, biến mất khi pop về screen khác. Implement: position: fixed; bottom: 0; với safe-area-inset-bottom, content padding-bottom += height CTA + safe area.
Implement React Router/Navigation
React Navigation (React Native) có StackNavigator built-in. Web app dùng React Router với history.push, hoặc Next.js App Router push qua Link.
Quan trọng: maintain scroll position của parent screen khi pop về. Browser history API hỗ trợ sẵn nhưng dễ bị mất khi dùng SPA route mà không cẩn thận setup.
Test back-forward navigation trên 3-5 path để verify.
Kết hợp pattern — đa số app dùng 2-3 pattern song song
Trong thực tế ít app chỉ dùng 1 pattern navigation. Đa số kết hợp 2-3 pattern theo cấu trúc layered.
Hiểu cách kết hợp giúp thiết kế navigation cho app phức tạp mà vẫn intuitive.
Bottom Tab + Stack
Bottom tab cho 4-5 destination chính, mỗi tab có stack riêng để push deeper. Shopee có 5 tab (Home, Mall, Live, Notif, Me).
Tap Home → list product (root) → tap product → ProductDetail (push lên Home stack) → back về list.
Tab Notif vẫn có stack riêng độc lập. Pattern này NN/g recommend cho 90% e-commerce app.
Đơn giản, intuitive, conversion cao.
Bottom Tab + Top Tab + Stack
Thêm top tab cho filter trong destination. Gmail (Bottom: Mail/Meet, Top in Mail: Primary/Promotions/Social, Stack: list → email detail).
TikTok (Bottom: Home/Discover/Inbox/Profile, Top in Home: For You/Following, Stack: feed → comment → user profile).
Kết hợp này phù hợp app content-heavy với 2 trục thông tin. Tránh dùng cho app đơn giản — over-engineering gây user confused giữa 2 tier nav cùng look.
Drawer + Stack
App có nhiều mục phụ, ít destination chính. Drawer chứa Inbox/Starred/Sent/Drafts/Settings, mỗi mục có stack riêng.
Apple Mail dùng pattern này (drawer-style navigation list ở root, push vào folder).
Pattern phù hợp app B2B nội bộ hoặc productivity tool. Discoverability thấp nhưng user expert quen pattern này, không phải vấn đề lớn.
Bottom Tab + FAB + Stack
Thêm FAB cho compose/create action. Twitter (Bottom 5 tab + FAB Compose + Stack).
Pattern hợp app có create flow rõ (post, message, document new).
FAB position bottom-right 16dp margin từ edge. Animation hide-on-scroll-down show-on-scroll-up nếu feed dài để không che content quan trọng.
Anti-pattern kết hợp
Nhiều entry point cho cùng 1 destination (vd “Profile” có cả ở Bottom Tab + Drawer + FAB) gây confusion. User không biết tap đâu, không nhớ pattern.
Drawer + Bottom Tab + Top Tab cùng có nhiều mục: user lạc giữa các nav. Đúng cách: mỗi destination 1 entry point chính, chọn 1 navigation pattern dominant, pattern phụ chỉ phục vụ subset cụ thể.
Accessibility cho navigation mobile
Navigation là entry point của app — accessibility quyết định toàn bộ app có usable cho user khuyết tật (visual impairment, motor impairment) hay không. WCAG 2.2 có nhiều rule cho nav, dưới đây 6 mục quan trọng nhất cho mobile.
Reference accessibility thiết kế web cho framework chung.
Touch target và focus visible
- Touch target >= 44×44px (WCAG 2.5.5 AAA): tab bar, hamburger, FAB, back button đều phải đạt. Visual có thể nhỏ hơn (icon 24×24) nhưng tap area extend ra 44×44 qua padding hoặc pseudo-element.
- Focus visible (WCAG 2.4.7): khi user dùng keyboard hoặc switch control device, focus ring phải visible rõ. Default browser focus ring là baseline.
- CSS:
:focus-visible { outline: 2px solid #0369a1; outline-offset: 2px; }.
ARIA labels và screen reader
- Hamburger button:
aria-label="Mở menu chính",aria-expanded="false"binding state. - Bottom tab:
role="tablist"cho container,role="tab"+aria-selected+aria-current="page"cho mỗi tab. - Drawer:
role="navigation"+aria-label="Main navigation". Test với VoiceOver iOS Settings → Accessibility và TalkBack Android Settings → Accessibility.
Skip link và contrast
- Skip link:
<a href="#main" class="skip-link">Skip to content</a>hidden ở top, hiện khi focus. CSS hide off-screen, focus thì transform về visible. - Cho phép keyboard user skip qua 5-10 nav item.
- Color contrast >= 5:1: label tab/menu pass WCAG 1.4.3 AA. Inactive tab gray quá nhạt (#9ca3af trên trắng chỉ 2.8:1) → fail.
- Dùng gray đậm hơn #475569 đạt 7.6:1. Tools test: WebAIM Contrast Checker.
- Reduced motion: user vestibular disorder bị chóng mặt với slide/parallax. Detect
@media (prefers-reduced-motion: reduce)và disable animation hoặc fade ngắn 100ms.
7 lỗi navigation mobile thường gặp khi audit
Audit Web22 cho 25+ ứng dụng di động/site khách 2024-2025, các lỗi sau lặp lại nhiều nhất. Đa số đến từ desktop-first thinking hoặc thiếu test thiết bị thật.
- Lỗi 1 — Hamburger trên màn chính có 4-5 destination: nhồi vào hamburger thay vì bottom tab khiến mỗi navigation tốn 2 tap. Conversion giảm 25-35%.
- Sửa: extract 4-5 mục chính ra bottom tab, giữ hamburger cho mục phụ.
- Lỗi 2 — Top tab quá nhiều (15+) không scroll snap: user scroll tab nửa chừng không biết còn bao nhiêu phía sau. Sửa:
scroll-snap-type: x mandatory+scroll-snap-align: start. - Hoặc giảm tab xuống <= 8, “More” dropdown cho phần dư.
- Lỗi 3 — FAB block content quan trọng: FAB Compose của social app đè timestamp + author của post cuối khi scroll cuối feed. Sửa: padding-bottom feed += FAB height + margin, hoặc auto-hide on scroll-down show on scroll-up.
- Lỗi 4 — Back button vắng mặt trên screen sâu: user vào từ deep link (notification, ads) không có previous screen → back button không có → user stuck. Sửa: nếu không có previous trong stack, hiển thị “Home” button thay vì hide back.
- Lỗi 5 — Tab label khác language: bottom tab có “Home” tiếng Anh, “Giỏ” tiếng Việt — inconsistent. Sửa: chọn 1 ngôn ngữ chuẩn (tiếng Việt nếu target VN): Trang chủ / Khám phá / Giỏ hàng / Đơn hàng / Tài khoản.
- Lỗi 6 — Drawer mở chậm vì lazy-load avatar: drawer 15 mục với avatar profile + icon SVG, mỗi cái fetch network. Mở mất 800-1500ms.
- Sửa: bundle icon vào sprite SVG hoặc icon font, preload avatar 80×80 ngay khi vào app.
- Lỗi 7 — Active state không rõ ràng: bottom tab active tab cùng màu inactive, chỉ khác opacity nhẹ. User không biết đang ở tab nào.
- Sửa: active có color contrast cao + indicator (underline, pill, icon filled vs outline). Test 5 user, nếu >= 2 user không biết tab nào → fail.
Câu hỏi thường gặp
Bottom tab bar có giới hạn 5 mục cứng không?
Apple HIG cho phép tối đa 5 tab, Material Design cũng vậy (Navigation Bar 3-5 destination). Lý do là tap area chia đều — 6 tab trên viewport 414px chỉ còn 69px/tab, dưới chuẩn 80-88px khuyến nghị.
Vượt 5 buộc dùng “More” overflow tab gom các mục phụ vào dropdown — pattern này clutter, NN/g chỉ trích. Đúng cách: phạm vi app xuống 5 destination chính, feature phụ access qua sub-page hoặc settings.
Khi nào dùng hamburger drawer thay bottom tab?
3 ngữ cảnh. App có 7+ destination ngang hàng (Gmail folder, Slack workspace).
Navigation phụ trong app có dominant pattern khác (Reddit có bottom tab nhưng drawer cho subreddit list). Destination thường truy cập qua deep link, navigation in-app chỉ backup (banking app — user vào từ notification).
Tránh dùng drawer làm primary nav cho consumer app shopping/social. Discoverability kém, conversion thấp hơn bottom tab 20-40%.
Drawer phù hợp B2B SaaS, productivity tool — user expert đã quen pattern.
Top tab và bottom tab có thể cùng tồn tại không?
Có và phổ biến. Bottom tab cho destination chính (Home/Search/Cart/Profile), top tab cho filter trong destination (in Home: For You / Following / Latest).
Gmail, TikTok, Twitter đều dùng kết hợp này.
Quan trọng: top tab phải clearly là sub-filter của bottom tab parent, không phải destination chính cạnh tranh — tránh user lạc. Visual hierarchy rõ qua font size, color, indicator style khác nhau.
FAB có chuẩn position bottom-right hay center?
Material Design chuẩn bottom-right 16dp margin từ edge. Center-bottom dùng khi FAB là action quan trọng nhất + bị bottom tab “đè” lên (Facebook camera). iOS HIG không quy định cứng vì FAB không phải native iOS.
Right-handed user 85-90% global → bottom-right tự nhiên hơn cho cầm phone tay phải. Lefty user có thể setting flip nhưng đa số app không hỗ trợ.
Chấp nhận trade-off này — phục vụ đa số 2026.
Stack navigation có cần animation transition không?
Có và đáng đầu tư. Animation transition (slide-in từ phải khi push, slide-out sang phải khi pop) tạo sense of direction — user cảm nhận đang đi sâu hay quay lại.
Native iOS có transition built-in 300ms.
React Navigation hỗ trợ sẵn cho React Native. Web app phải custom — dùng Framer Motion AnimatePresence + key prop trên Outlet.
Duration 250-350ms, easing decelerate. Bỏ animation hoàn toàn khiến app feel “web-like” thay vì native.
Navigation cho web app khác native app thế nào?
Web app trên mobile browser thiếu vài thứ. Không có status bar control (notch handle bằng safe-area-inset CSS), không có swipe-back gesture (chỉ browser back hoặc custom button), animation transition phải JS-implemented không native.
Pattern phổ biến cho mobile web: bottom tab fixed (CSS position: fixed), drawer overlay (dialog element hoặc portal), FAB sticky. Tránh imitate native quá kỹ — user expect web behavior, vd swipe-down to refresh chỉ implement nếu thực sự cần.
Có nên dùng sidebar trái fix cho web mobile không?
Không, đã outdated. Sidebar trái fix chiếm 80% viewport phone là pattern web cũ pre-responsive 2010-2014.
Mobile chuẩn 2026: hide sidebar bằng drawer pattern (slide-in từ trái khi tap hamburger), hoặc thay bằng bottom tab.
Site WordPress legacy với sidebar widget đầy thường gặp issue này. Refactor vào drawer + bottom tab khi rebuild theme.
Xem thiết kế mobile-first 2026 cho cách setup mobile nav chuẩn.
Tổng kết và bước tiếp theo
Navigation ứng dụng di động 2026 dominant với kết hợp Bottom Tab + Stack cho 90% e-commerce và content app. Bottom Tab gần thumb zone, conversion cao.
Hamburger Drawer chỉ dùng cho app > 7 destination hoặc user expert quen pattern. FAB cho action chính rõ ràng.
Top Tab cho filter sub-destination.
Bài liên quan trong cluster UI/UX mobile:
- Touch target tối thiểu — iOS 44pt + Android 48dp — chuẩn tap area cho mọi nav element.
- Thiết kế mobile-first 2026 — cascade CSS + breakpoint — context mobile-first cho navigation design.
- Bottom sheet mobile — 3 biến thể và snap point — pattern overlay bổ sung cho navigation.
- Onboarding ứng dụng di động — 4 pattern và A/B test — first-time UX dẫn dắt user qua navigation.
Web22 audit + thiết kế lại navigation mobile cho e-commerce, app SaaS và blog VN — chọn pattern phù hợp use case (bottom tab cho consumer shop, drawer cho enterprise tool), implement React/Vue/WordPress với accessibility WCAG 2.2 AA, test trên 5+ thiết bị thật. Đội UI Designer Web22 — wireframe + handoff Dev Mode với report cụ thể trong 5-7 ngày + đề xuất rework theo metric.


