Giao diện nâng cao — Animation & Responsive
Mục tiêu
Yêu cầu AI tạo hiệu ứng chuyển động (animation) và đảm bảo app hiển thị tốt trên mọi thiết bị (responsive design).
Sau bài này, bạn sẽ:
- ✅ Biết cách prompt AI tạo responsive layout cho desktop, tablet, mobile
- ✅ Yêu cầu AI thêm animation chuyên nghiệp mà không cần biết CSS
- ✅ Tự kiểm tra UI/UX bằng checklist dành cho non-designer
- ✅ Xử lý được các lỗi phổ biến về giao diện trên mobile
Nội dung chính
4.1 — Responsive: “Cùng nội dung, khác hình dáng”
DESKTOP (>1024px) TABLET (768px) MOBILE (<480px)
┌──────────────────┐ ┌──────────────┐ ┌──────────┐
│ Nav │ Content │ │ Nav │ │ ☰ Menu │
│ │ ┌──┐ ┌──┐ │ │ ┌──┐ ┌──┐ │ │ ┌──────┐ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ └──┘ └──┘ │ │ └──┘ └──┘ │ │ └──────┘ │
│ │ ┌──┐ ┌──┐ │ │ ┌──┐ ┌──┐ │ │ ┌──────┐ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ └──┘ └──┘ │ │ └──┘ └──┘ │ │ └──────┘ │
└──────────────────┘ └──────────────┘ └──────────┘
4 cột 2 cột 1 cột
Sidebar hiện Sidebar ẩn Menu hamburger
Prompt mẫu cho responsive (chi tiết):
Đảm bảo toàn bộ app responsive trên 3 breakpoints chính.
Desktop (>1024px):
- Layout grid 4 cột cho danh sách items
- Sidebar bên trái luôn hiện, width 250px
- Navigation bar ngang, hiện đầy đủ tất cả links
- Font size mặc định (16px body)
Tablet (768-1024px):
- Grid chuyển thành 2 cột
- Sidebar ẩn, thay bằng top navigation bar
- Các card giữ nguyên padding nhưng giảm margin
- Touch target: tất cả nút bấm tối thiểu 44x44px
Mobile (<768px):
- Grid 1 cột, full width
- Menu hamburger (icon ☰) thay cho navigation bar
- Menu mở ra overlay toàn màn hình khi bấm
- Font tăng 10% để dễ đọc trên màn hình nhỏ
- Nút bấm tối thiểu 48x48px, cách nhau ít nhất 8px
- Tất cả ảnh max-width: 100%, height: auto
- Form input full width, height tối thiểu 48px
- Scroll horizontal bị chặn (không scroll ngang)
Dùng Tailwind CSS responsive prefixes (md:, lg:).
Test bằng Chrome DevTools → Toggle Device Toolbar (Ctrl+Shift+M).
Mẹo: Thiết kế mobile-first nghĩa là viết CSS cho mobile trước, rồi thêm cho tablet và desktop. Trong Tailwind, code không có prefix là mobile,
md:là tablet,lg:là desktop. Ví dụ:grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4.
4.2 — Animation: “Chuyển động tạo cảm xúc”
Không cần biết CSS animation. Chỉ cần mô tả:
Thêm animation cho app với 2 cấp độ:
CẤP 1 — CSS Transitions (đơn giản, nhẹ):
1. Hover trên card: scale lên 1.03, shadow đậm hơn, transition 0.2s ease
2. Hover trên nút: background sáng hơn 10%, transition 0.15s
3. Focus trên input: border đổi màu accent, transition 0.2s
4. Link navigation: underline slide vào từ trái khi hover
CẤP 2 — Framer Motion (phức tạp, đẹp):
5. Khi trang load: các card xuất hiện từ dưới lên (fade + translateY),
lần lượt mỗi card cách nhau 0.1 giây (stagger effect)
6. Khi thêm item mới: item slide vào từ bên phải, duration 0.3s
7. Khi xóa item: item fade out + scale nhỏ lại, duration 0.2s
8. Page transition: fade giữa các trang, duration 0.2s
9. Modal: fade in + scale từ 0.95 → 1.0, backdrop blur
Lưu ý quan trọng:
- Tất cả animation phải có prefers-reduced-motion: reduce
(tắt animation cho user nhạy cảm với chuyển động)
- Duration KHÔNG quá 0.4s (người dùng sẽ cảm thấy chậm)
- Dùng ease-out cho enter, ease-in cho exit
- KHÔNG animation cho scroll (gây lag trên mobile)
Prompt nâng cao — Micro-interactions:
Thêm micro-interactions để app cảm giác "sống" hơn:
1. Nút "Like" / "Hoàn thành":
- Bấm → icon nhảy lên 1 chút (bounce) + đổi màu
- Confetti nhỏ bay ra nếu hoàn thành task (tuỳ chọn)
2. Counter / số liệu:
- Khi data load xong, số chạy từ 0 đến giá trị thật
- Duration 0.8s, easing ease-out
3. Toggle switch:
- Slide mượt giữa on/off
- Background đổi màu gradient
4. Loading skeleton:
- Thay vì spinner, dùng skeleton placeholder
- Shimmer effect (sáng chạy từ trái qua phải)
Dùng Framer Motion cho tất cả. KHÔNG dùng setTimeout/setInterval
cho animation — dùng requestAnimationFrame hoặc animation library.
Mẹo: Animation đẹp nhất là animation bạn KHÔNG nhận ra. Nếu user phải chờ animation xong mới thao tác được → animation đó quá chậm. Quy tắc: UI animation nên dưới 300ms, page transition dưới 200ms.
4.3 — Kỹ thuật review UI/UX không cần biết design
Checklist tự kiểm tra:
┌────────────────────────────────────────────────────────┐
│ CHECKLIST UI/UX CHO NON-DESIGNER │
│ │
│ □ Mở app trên điện thoại → có đọc được chữ không? │
│ □ Nút bấm có đủ lớn để bấm bằng ngón tay không? │
│ □ Màu chữ vs màu nền → có đọc rõ không? (contrast) │
│ □ Mỗi trang có mục đích rõ ràng không? │
│ □ User mới vào có biết phải làm gì đầu tiên không? │
│ □ Loading state: khi dữ liệu đang tải, user thấy gì?│
│ □ Error state: khi lỗi xảy ra, user thấy gì? │
│ □ Empty state: khi chưa có data, trang có trống trơn? │
│ │
└────────────────────────────────────────────────────────┘
Cách test responsive nhanh nhất:
- Mở app trên Chrome
- Bấm
Ctrl+Shift+M(hoặcCmd+Shift+Mtrên Mac) → Device Toolbar - Chọn các thiết bị phổ biến: iPhone 14 Pro, iPad Air, Samsung Galaxy S21
- Kiểm tra từng trang → ghi lại các vấn đề
- Paste danh sách vấn đề cho AI: “Sửa các vấn đề responsive sau: [danh sách]”
Mẹo: Test trên điện thoại thật luôn tốt hơn Chrome DevTools. DevTools mô phỏng kích thước màn hình nhưng không mô phỏng được cảm giác bấm nút, scroll, hay tốc độ mạng 4G. Deploy lên Vercel (miễn phí) rồi mở trên điện thoại là cách test chính xác nhất.
Lỗi thường gặp
Vấn đề: Animation bị giật (janky) trên mobile — không mượt như trên desktop.
→ Giải pháp: Chỉ animate 2 thuộc tính: transform và opacity. KHÔNG animate width, height, top, left, margin, padding — chúng gây reflow, rất nặng. Prompt AI: “Chuyển tất cả animation sang dùng transform thay vì position/margin.”
Vấn đề: Giao diện bị vỡ trên mobile — text tràn ra ngoài, nút bấm bị cắt.
→ Giải pháp: Kiểm tra 3 thứ: (1) Có overflow-x: hidden trên html không? (2) Có element nào set width cố định (px) thay vì % hoặc vw? (3) Ảnh có max-width: 100% chưa? Prompt AI: “Tìm tất cả element có width cố định (px) và chuyển sang responsive (%, vw, hoặc max-width).”
Vấn đề: Menu hamburger mở ra nhưng không đóng được, hoặc click vào link không đóng menu. → Giải pháp: Prompt AI: “Sửa menu hamburger: (1) Click vào link trong menu → menu tự đóng + navigate. (2) Click ra ngoài menu → menu đóng. (3) Bấm nút ☰ lần nữa → menu đóng. (4) Scroll khi menu mở → body không scroll.”
Vấn đề: Font quá nhỏ trên mobile, user phải zoom để đọc.
→ Giải pháp: Thêm <meta name="viewport" content="width=device-width, initial-scale=1"> trong HTML head. Font body tối thiểu 16px trên mobile (tránh iOS auto-zoom khi focus input). Prompt AI: “Kiểm tra font-size trên mobile, đảm bảo tối thiểu 16px cho body text và 14px cho caption.”
Vấn đề: Animation chạy khi page load xong nhưng user không thấy (element ở dưới fold). → Giải pháp: Dùng Intersection Observer — chỉ trigger animation khi element xuất hiện trong viewport. Prompt AI: “Chuyển tất cả scroll animation sang dùng Intersection Observer, chỉ animate khi element visible.”
Bài tập thực hành
Nhiệm vụ:
Các bước thực hiện:
- Kiểm tra đồ án bằng Checklist UI/UX trên — ghi lại các vấn đề (~5 phút)
- Dùng AI thêm responsive cho toàn bộ app (~10 phút)
- Thêm ít nhất 3 animation: hover effect, page load, thêm/xóa item (~10 phút)
- Test trên điện thoại thật hoặc Chrome DevTools với 3 thiết bị (~5 phút)
Tiêu chí hoàn thành:
- App hiển thị tốt trên iPhone (375px width) — không bị vỡ layout
- App hiển thị tốt trên iPad (768px width) — grid 2 cột
- Có ít nhất 3 animation mượt mà (không giật)
- Menu hamburger hoạt động trên mobile
- Tất cả nút bấm đủ lớn trên mobile (min 44x44px)
Gợi ý nếu bị stuck: Nếu responsive quá phức tạp, bắt đầu từ 1 trang quan trọng nhất (trang chính). Khi trang đó responsive xong, dùng cùng pattern cho các trang còn lại. Prompt AI: “Dùng cùng responsive pattern như trang Home cho trang [tên trang].”
Thời gian: 30 phút Deliverable: Screenshot app trên desktop + screenshot trên điện thoại + commit
Kiểm tra kiến thức
1. Trong Tailwind CSS, responsive prefix nào dùng cho tablet?
2. Khi làm animation, chỉ nên animate 2 thuộc tính CSS nào để tránh giật?
3. Nút bấm trên mobile nên có kích thước tối thiểu bao nhiêu?
4. Thiết kế mobile-first nghĩa là gì?
5. Duration animation cho UI nên giữ dưới bao nhiêu?