Đang tải...

Ếch Trendy

Cùng chú ếch nhỏ khám phá thế giới Web đầy biến động. Cập nhật trending nhanh như cách ếch đớp mồi! ⌨️🌿


0

Web Accessibility 2026: Làm website chuẩn WCAG 2.2 để vừa dễ dùng vừa chuẩn SEO

Ếch Trendy
Ếch Trendy

2 tháng trước · 8 phút đọc

Tại sao accessibility quan trọng hơn bao giờ hết

Mình từng nghĩ accessibility chỉ là thêm alt vào ảnh cho có. Rồi một lần audit lại codebase cũ, axe DevTools báo hơn 80 lỗi chỉ trong một trang. Lỗi form không có label. Button không có tên. Modal bẫy focus mãi không ra. Người dùng dùng screen reader không điều hướng được gì.

Không chỉ là vấn đề đạo đức. hơn 15% người dùng internet toàn cầu có ít nhất một dạng khuyết tật. Với website Việt Nam, con số này vẫn là hàng triệu người thật đang cố dùng sản phẩm của bạn.

346751 Phần lớn lỗi accessibility có thể fix chỉ trong vài dòng code

Và Google cũng đang nhìn vào đây. Core Web Vitals tốt nhưng accessibility kém vẫn ảnh hưởng ranking. Semantic HTML đúng chuẩn giúp crawler hiểu cấu trúc trang rõ hơn, cải thiện snippet và rich results. Nói cách khác, làm accessibility tốt là làm SEO tốt - hai mục tiêu, một công sức.


Semantic HTML - nền tảng không thể bỏ qua

Trước khi nghĩ đến ARIA, hãy dùng đúng HTML. Đây là nguyên tắc số một của WCAG: dùng element phù hợp với nghĩa của nó.

<!-- ❌ Sai: div làm nút bấm, không focus được bằng bàn phím -->
<div class="btn" onclick="submit()">Gửi form</div>

<!-- ✅ Đúng: button có sẵn keyboard focus, role, và event -->
<button type="submit">Gửi form</button>

Một số lỗi semantic phổ biến nhất mình gặp khi review code:

  • Dùng <div> thay <button> hoặc <a> cho các phần tử tương tác
  • Không dùng <nav>, <main>, <header>, <footer> - screen reader dùng các landmark này để điều hướng nhanh
  • Heading nhảy cấp lung tung: H1 → H3, bỏ H2
  • Form không có <label> gắn với <input>

346752 Heading hierarchy rõ ràng giúp screen reader jump nhanh giữa các mục

Khi dùng đúng semantic HTML, bạn không cần viết thêm gì nhiều. <button> tự có role="button", focusable, và kích hoạt bằng Enter/Space. <a href> tự có role="link". <nav> tự báo với screen reader đây là vùng điều hướng. Miễn phí, không tốn công.

Một quy tắc đơn giản: nếu bạn đang viết ARIA để bù cho một element, hãy hỏi xem có element HTML nào phù hợp hơn không. Thường là có.


ARIA labels - dùng đúng chỗ, đừng lạm dụng

ARIA (Accessible Rich Internet Applications) không phải phép màu. Nó bổ sung thông tin ngữ nghĩa cho các element mà HTML thuần không diễn đạt đủ. Nhưng ARIA sai còn tệ hơn không có ARIA.

Ba attribute hay dùng nhất:

aria-label - gán tên cho element khi không có text hiển thị:

<!-- Icon button không có text -->
<button aria-label="Đóng dialog">
  <svg>...</svg>
</button>

<!-- Search input có placeholder nhưng không có label -->
<input
  type="search"
  aria-label="Tìm kiếm sản phẩm"
  placeholder="Nhập tên sản phẩm..."
/>

aria-describedby - liên kết thông tin bổ sung (thường dùng cho error message):

<input
  type="email"
  id="email"
  aria-describedby="email-error"
  aria-invalid="true"
/>
<span id="email-error" role="alert">
  Email không hợp lệ. Vui lòng nhập đúng định dạng.
</span>

aria-live - thông báo dynamic content thay đổi:

<!-- Thông báo kết quả lọc sản phẩm -->
<div aria-live="polite" aria-atomic="true">
  Tìm thấy 12 sản phẩm
</div>

346753 aria-live giúp screen reader đọc cập nhật động mà không cần focus thủ công

Lỗi phổ biến nhất với ARIA: gán role="button" cho <div> rồi quên xử lý keyboard event. Screen reader sẽ thông báo đây là button, nhưng nhấn Enter/Space không làm gì. Tệ hơn là không có ARIA.

// Nếu bắt buộc phải dùng div làm button (trường hợp rất hiếm)
// thì phải xử lý đầy đủ
const fakeBtn = document.querySelector('[role="button"]');
fakeBtn.addEventListener('keydown', (e) => {
  // Kích hoạt khi nhấn Enter hoặc Space
  if (e.key === 'Enter' || e.key === ' ') {
    e.preventDefault();
    fakeBtn.click();
  }
});

Keyboard navigation và focus management

Khoảng 33.3% of respondents with mobility impairments used keyboard or keyboard-like device as primary means of web navigation (WebAIM Survey of Users with Motor Disabilities) người dùng điều hướng web bằng bàn phím hoàn toàn - không có chuột. Thêm vào đó là tất cả người dùng screen reader. Nếu website không dùng được bằng Tab/Shift+Tab/Enter/Escape, một phần không nhỏ người dùng bị loại khỏi sản phẩm của bạn.

Test đơn giản nhất: mở website, bỏ chuột xuống, dùng Tab để điều hướng. Bạn có thể trả lời được không: focus đang ở đâu? Thứ tự có hợp lý không? Có chỗ nào focus bị "mất" không?

/* KHÔNG bao giờ xóa focus outline mà không thay thế */
/* ❌ */
* { outline: none; }

/* ✅ Thay bằng custom focus style đẹp hơn */
:focus-visible {
  outline: 2px solid #0d9488;
  outline-offset: 2px;
  border-radius: 4px;
}

346754 Focus visible rõ ràng là quyền lợi của người dùng, không phải tùy chọn

Với modal dialog, focus management quan trọng đặc biệt. Khi modal mở, focus phải chuyển vào trong modal. Khi đóng, focus phải trở về element đã trigger modal. Và trong khi modal mở, Tab không được thoát ra ngoài (focus trap).

// Focus trap đơn giản cho modal
function trapFocus(modalElement) {
  // Lấy tất cả element có thể focus trong modal
  const focusable = modalElement.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const firstEl = focusable[0];
  const lastEl = focusable[focusable.length - 1];

  modalElement.addEventListener('keydown', (e) => {
    if (e.key !== 'Tab') return;

    if (e.shiftKey) {
      // Shift+Tab từ element đầu tiên → nhảy về cuối
      if (document.activeElement === firstEl) {
        e.preventDefault();
        lastEl.focus();
      }
    } else {
      // Tab từ element cuối → nhảy về đầu
      if (document.activeElement === lastEl) {
        e.preventDefault();
        firstEl.focus();
      }
    }
  });
}

Escape để đóng modal cũng là kỳ vọng tiêu chuẩn - người dùng bàn phím và screen reader đều expect điều này.


Color contrast và visual accessibility

Color contrast là lỗi phổ biến nhất trong WCAG. 81.0% (WebAIM Million 2024) website thất bại tiêu chí này theo khảo sát của WebAIM.

WCAG 2.2 yêu cầu:

  • Text thường: contrast ratio tối thiểu 4.5:1 (Level AA)
  • Text lớn (18px+ regular hoặc 14px+ bold): tối thiểu 3:1
  • UI components và đồ họa (border input, icon có nghĩa): tối thiểu 3:1
/* Ví dụ kiểm tra contrast */

/* ❌ Gray text trên white - thường fail AA */
.text-light {
  color: #aaaaaa; /* contrast ~2.3:1 với white - FAIL */
  background: #ffffff;
}

/* ✅ Đủ contrast */
.text-accessible {
  color: #595959; /* contrast 7:1 với white - PASS AAA */
  background: #ffffff;
}

/* Đừng dùng chỉ màu để truyền thông tin */
/* ❌ Chỉ đổi màu text thành đỏ để báo lỗi */
.error { color: red; }

/* ✅ Kết hợp màu + icon + text */
.error {
  color: #dc2626;
  /* Thêm icon ⚠ hoặc text "Lỗi:" trước message */
}

346755 Đừng dùng mình màu sắc để truyền thông tin - người mù màu sẽ bỏ sót

WCAG 2.2 bổ sung một tiêu chí mới liên quan đến focus indicator (2.4.11): focus visible phải đủ kích thước và contrast. Trước đây nhiều site chỉ cần có focus outline là xong, giờ phải đảm bảo outline đó thực sự nhìn được.

Tool nhanh để check: WebAIM Contrast Checker. Paste màu HEX vào, nó tính ratio ngay. Hoặc dùng browser DevTools - Chrome DevTools giờ có built-in contrast checker khi inspect element.

Một điều hay bị bỏ qua: focus indicator cũng phải đủ contrast. Nếu bạn dùng outline màu xanh nhạt trên nền trắng, người low vision vẫn không thấy.


Testing tools: axe, WAVE và Lighthouse

Kiểm tra accessibility bằng tay tốt nhưng không thể phủ hết. Ba tool dưới đây cover phần lớn lỗi có thể tự động phát hiện.

axe DevTools là lựa chọn mình dùng nhiều nhất. Cài extension vào Chrome/Firefox, mở DevTools, chọn tab axe. Nó phân tích trang và liệt kê lỗi theo mức độ nghiêm trọng, kèm link đến giải thích và cách fix. Điểm mạnh: ít false positive, giải thích rõ ràng, có thể tích hợp vào CI/CD qua axe-core trên npm.

346756 axe DevTools phân loại lỗi theo impact: critical, serious, moderate, minor

WAVE (Web Accessibility Evaluation Tool) cho cái nhìn trực quan hơn - nó overlay icon lên trang để chỉ rõ lỗi ở đâu. Tiện khi muốn giải thích cho người không phải dev. Dùng WAVE online

Lighthouse built-in trong Chrome DevTools (tab Lighthouse → chọn Accessibility). Cho điểm 0-100, nhanh, tiện cho việc theo dõi trend. Nhưng lưu ý: điểm 100 không có nghĩa là accessible 100% - Lighthouse chỉ tự động phát hiện được khoảng 30-40% of WCAG accessibility issues detectable by automated tools like Lighthouse and axe; Deque's axe-core research found 57.38% of known violations detectable in real-world audits (Deque axe-core research and industry consensus (2023-2024)) lỗi accessibility.

# Chạy Lighthouse accessibility audit bằng CLI
npx lighthouse https://example.com \
  --only-categories=accessibility \
  --output=html \
  --output-path=./accessibility-report.html

Sau khi fix lỗi tool báo, bắt buộc phải test thủ công:

  1. Điều hướng toàn trang bằng Tab - không dùng chuột
  2. Bật screen reader (VoiceOver trên Mac, NVDA hoặc JAWS trên Windows, TalkBack trên Android) và nghe thử
  3. Zoom browser lên 200% - layout có vỡ không?
  4. Tắt CSS - nội dung có còn đọc được theo thứ tự hợp lý không?

Trang web dùng cookie để hoạt động và đo hiệu quả quảng cáo. Xem chính sách bảo mật