11 KiB
GoodGo Platform Kiểm Toán Khả Năng Tiếp Cận - Tài Liệu Tham Khảo Nhanh
Ngày: 10 tháng 4 năm 2026 | Trạng thái: Tuân thủ WCAG 2.1 AA ở mức 70–75%
📊 Chỉ Số Chính
| Chỉ số | Số lượng | Trạng thái |
|---|---|---|
| Tổng số tệp đã phân tích | 90+ | ✅ |
| Thuộc tính ARIA tìm thấy | 75 | ✅ |
| Tệp sử dụng ARIA | 14 | ✅ |
| Vấn đề nghiêm trọng | 2 | 🔴 |
| Vấn đề lớn | 3 | 🟡 |
| Vấn đề nhỏ | 2 | 🟢 |
🔴 VẤN ĐỀ NGHIÊM TRỌNG (Phải Sửa)
1. Thành Phần Dialog Thiếu Khả Năng Tiếp Cận
Tệp: apps/web/components/ui/dialog.tsx
Vấn đề:
- Thiếu
role="dialog" - Thiếu
aria-modal="true" - Không có bẫy tiêu điểm (focus trap)
- Không xử lý phím Escape
- Phần nền không bị ẩn khỏi trình đọc màn hình
Thời gian sửa: 2–3 giờ | Ưu tiên: 1
Danh sách kiểm tra sửa nhanh:
- Thêm role="dialog" vào vùng chứa dialog
- Thêm aria-modal="true"
- Triển khai trình lắng nghe phím Escape
- Thêm aria-hidden="true" vào lớp phủ nền
- Kiểm tra với trình đọc màn hình NVDA
2. Nút Hình Thu Nhỏ Trong Thư Viện Ảnh Thiếu Nhãn
Tệp: apps/web/components/listings/image-gallery.tsx:69-84
Vấn đề: Các nút hình thu nhỏ thiếu aria-label
Thời gian sửa: 15–30 phút | Ưu tiên: 2
Sửa nhanh:
// Thêm vào mỗi nút hình thu nhỏ:
aria-label={`Select image ${index + 1}${img.caption ? ': ' + img.caption : ''}`}
aria-pressed={index === selectedIndex}
🟡 VẤN ĐỀ LỚN (Nên Sửa)
1. Tiêu Đề Layout Admin Thiếu Vai Trò Banner
Tệp: apps/web/app/[locale]/(admin)/layout.tsx:134
Sửa nhanh:
// Đổi từ:
<header className="sticky...">
// Sang:
<header role="banner" className="sticky...">
Thời gian sửa: 2 phút | Ưu tiên: 3
2. Độ Tương Phản Màu Chưa Được Kiểm Tra
Vấn đề: Các biến CSS đã được định nghĩa nhưng tỷ lệ tương phản chưa được kiểm tra Tác động: Có thể vi phạm WCAG 1.4.3 Thời gian sửa: 4–6 giờ kiểm tra
Danh sách kiểm tra:
- Trích xuất giá trị biến CSS từ globals.css
- Kiểm tra bằng WebAIM Contrast Checker
- Xác minh tỷ lệ 4.5:1 cho văn bản thông thường (WCAG AA)
- Xác minh tỷ lệ 7:1 cho tuân thủ AAA
- Kiểm tra ở cả chế độ sáng và tối
3. Ô Nhập Tìm Kiếm Trang Đầu Thiếu Nhãn Hiển Thị
Tệp: apps/web/app/[locale]/(public)/page.tsx:87-92
Sửa nhanh:
<div className="flex flex-col gap-1">
<label htmlFor="search-input" className="sr-only">
{t('landing.searchPlaceholder')}
</label>
<Input
id="search-input"
placeholder={t('landing.searchPlaceholder')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
Thời gian sửa: 30 phút | Ưu tiên: 4
🟢 VẤN ĐỀ NHỎ (Nên Có)
1. aria-label Thừa Trên Văn Bản Đã Hiển Thị
Tệp: apps/web/app/[locale]/(dashboard)/layout.tsx:125
Vấn đề: Các liên kết có aria-label trong khi văn bản đã hiển thị
Khuyến nghị: Xóa các aria-label thừa — văn bản hiển thị sẵn tốt hơn cho khả năng tiếp cận
✅ NHỮNG GÌ ĐANG HOẠT ĐỘNG TỐT
Biểu Mẫu Xác Thực
- ✅ Tất cả các ô nhập có nhãn hiển thị với
<Label htmlFor="id"> - ✅ Thông báo lỗi được liên kết qua
aria-describedby - ✅ Trạng thái không hợp lệ được đánh dấu bằng
aria-invalid - ✅ Nút hiện/ẩn mật khẩu có
aria-labelđúng chuẩn - Ví dụ:
apps/web/app/[locale]/(auth)/login/page.tsx
Liên Kết Bỏ Qua Nội Dung (Skip-to-Content)
- ✅ Được triển khai đúng chuẩn với khả năng hiển thị tiêu điểm
- ✅ Ẩn theo mặc định, hiển thị khi được tiêu điểm
- ✅ Liên kết đến
id="main-content" - Ví dụ:
apps/web/app/[locale]/layout.tsx:105-110
Điều Hướng
- ✅ Tất cả các nav có
aria-label - ✅ Nút chuyển đổi menu di động có nhãn động
- ✅ Biểu tượng được ẩn đúng chuẩn với
aria-hidden="true" - Ví dụ: Tất cả các tệp layout
Tìm Kiếm & Bộ Lọc
- ✅ Phần bộ lọc có
role="search" - ✅ Tất cả các ô select có
aria-label - ✅ Ô nhập kiểu dải (range) được gắn nhãn đúng chuẩn
- Ví dụ:
apps/web/components/search/filter-bar.tsx
Thư Viện Ảnh
- ✅ Các nút Trước/Sau có aria-label
- ✅ Cấu trúc ngữ nghĩa tốt
- Ví dụ:
apps/web/components/listings/image-gallery.tsx:47, 54
📋 DANH SÁCH KIỂM TRA THỬ NGHIỆM
Trước Khi Triển Khai
- Sửa khả năng tiếp cận của thành phần dialog
- Thêm nhãn cho các nút hình thu nhỏ
- Thêm vai trò banner vào tiêu đề admin
- Chạy kiểm toán khả năng tiếp cận Lighthouse (mục tiêu: 90+)
- Kiểm tra với trình đọc màn hình NVDA
- Kiểm tra điều hướng bàn phím (Tab, Shift+Tab, Enter, Escape)
- Xác minh tỷ lệ tương phản màu sắc
- Kiểm tra chuyển đổi giao diện (chế độ sáng/tối)
Kiểm Tra Trình Đọc Màn Hình (NVDA)
- Biểu mẫu đăng nhập: Có thể điền trường, nghe thông báo lỗi
- Điều hướng: Có thể điều hướng menu, hiểu trang hiện tại
- Tìm kiếm: Có thể tìm và gửi biểu mẫu tìm kiếm
- Hộp thoại: Có thể mở, tương tác, đóng bằng phím Escape
- Thư viện ảnh: Có thể chọn ảnh, nghe ảnh nào đang được chọn
- Menu di động: Có thể mở/đóng, nút chuyển đổi hoạt động bình thường
Điều Hướng Bàn Phím
- Tab: Di chuyển qua tất cả các phần tử tương tác theo thứ tự hợp lý
- Shift+Tab: Di chuyển ngược lại qua các phần tử
- Enter: Kích hoạt nút/liên kết/gửi biểu mẫu
- Space: Kích hoạt nút, bật/tắt hộp kiểm
- Escape: Đóng modal/menu
- Phím mũi tên: Hoạt động trong dropdown/băng chuyền
🎯 Lộ Trình Ưu Tiên
Tuần 1 (40 giờ)
-
Sửa Thành Phần Dialog (2–3 giờ)
- Thêm role, aria-modal, focus trap, xử lý phím Escape
- Kiểm tra với trình đọc màn hình
-
Thêm Nhãn Hình Thu Nhỏ (0,5 giờ)
- Thêm aria-label vào các nút hình thu nhỏ
- Kiểm tra
-
Sửa Tiêu Đề Admin (0,1 giờ)
- Thêm role="banner"
-
Xác Minh Tương Phản (6–8 giờ)
- Trích xuất biến CSS
- Kiểm tra tất cả các tổ hợp
- Ghi lại kết quả
- Điều chỉnh nếu cần
-
Thêm Nhãn Trang Đầu (0,5 giờ)
- Thêm nhãn hiển thị vào ô nhập tìm kiếm
-
Kiểm Tra Trình Duyệt (8 giờ)
- Kiểm tra NVDA
- Kiểm tra Chrome/Firefox/Safari
- Kiểm tra trên thiết bị di động
Tuần 2 (20 giờ)
- Xóa Nhãn Thừa (0,5 giờ)
- Thêm Liên Kết Bỏ Qua Bổ Sung (2–3 giờ)
- Kiểm Tra Toàn Diện (8 giờ)
- Sửa Các Vấn Đề Phát Hiện (6 giờ)
📁 Tài Liệu Tham Chiếu Tệp
Các Tệp Quan Trọng Cần Xem Xét/Sửa
apps/web/components/ui/dialog.tsx- 🔴 CẦN VIẾT LẠIapps/web/components/listings/image-gallery.tsx- 🔴 CẦN SỬA NHỎapps/web/app/[locale]/(admin)/layout.tsx- 🟡 THÊM ROLEapps/web/app/globals.css- 🟡 XÁC MINH MÀU SẮC (chưa kiểm toán)
Các Tệp Có Khả Năng Tiếp Cận Tốt
apps/web/app/[locale]/(public)/layout.tsx- ✅ XUẤT SẮCapps/web/app/[locale]/(auth)/login/page.tsx- ✅ XUẤT SẮCapps/web/app/[locale]/(auth)/register/page.tsx- ✅ XUẤT SẮCapps/web/components/ui/button.tsx- ✅ TỐTapps/web/components/ui/input.tsx- ✅ TỐTapps/web/components/ui/label.tsx- ✅ TỐTapps/web/components/ui/select.tsx- ✅ TỐTapps/web/components/search/filter-bar.tsx- ✅ TỐT
🔍 Ví Dụ Mã
Ví Dụ Sử Dụng ARIA Tốt
// Tốt: aria-label động cập nhật theo trạng thái
<button
aria-label={mobileMenuOpen ? t('nav.closeMenu') : t('nav.openMenu')}
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
{mobileMenuOpen ? <X /> : <Menu />}
</button>
Ví Dụ Khả Năng Tiếp Cận Biểu Mẫu
// Tốt: Liên kết nhãn đúng chuẩn + xử lý lỗi
<div className="space-y-2">
<Label htmlFor="phone">{t('phone')}</Label>
<Input
id="phone"
type="tel"
aria-describedby={errors.phone ? 'phone-error' : undefined}
aria-invalid={!!errors.phone}
{...register('phone')}
/>
{errors.phone && (
<p id="phone-error" role="alert">{errors.phone.message}</p>
)}
</div>
Ví Dụ Biểu Mẫu Tìm Kiếm
// Tốt: Vai trò ngữ nghĩa đúng chuẩn với các điều khiển được gắn nhãn
<form role="search" aria-label={t('filters')}>
<Select aria-label={t('allTransactions')}>
{/* options */}
</Select>
</form>
📞 Tài Nguyên
Tài Liệu
- Báo cáo kiểm toán đầy đủ:
ACCESSIBILITY_AUDIT_2026-04-10.md - Kết quả chi tiết trên 15 phần
- Phân tích từng tệp
- Đánh giá tuân thủ WCAG 2.1
Công Cụ Kiểm Tra
- Axe DevTools: Tiện ích mở rộng Chrome/Firefox để kiểm tra nhanh
- Lighthouse: Tích hợp trong Chrome DevTools
- WebAIM Contrast Checker: https://webaim.org/resources/contrastchecker/
- NVDA: Trình đọc màn hình miễn phí - https://www.nvaccess.org/
Tài Nguyên Học Tập
📝 Ghi Chú
Phạm vi kiểm toán: apps/web (giao diện Next.js 15) Số tệp đã phân tích: 90+ tệp TSX/JSX Thời gian đạt tuân thủ AA: 4–6 ngày làm toàn thời gian Bảo trì liên tục: Nên tích hợp vào CI/CD và đào tạo lập trình viên
Bước tiếp theo:
- Xem xét báo cáo kiểm toán đầy đủ (1552 dòng)
- Tạo ticket Jira cho mỗi vấn đề
- Phân công nhiệm vụ cho nhóm phát triển
- Lên lịch kiểm tra khả năng tiếp cận
- Lập kế hoạch buổi đào tạo lập trình viên