- vừa được xem lúc

Đừng phá hỏng Web: Hướng dẫn Accessibility với ARIA cho lập trình viên

0 0 3

Người đăng: Gung Typical

Theo Viblo Asia

Lỗi có thể tốn hàng triệu đô

<!-- This looks fine, works fine, but breaks for 1 billion users -->
<div class="btn" onclick="submit()"> Submit Form
</div> <!-- This actually works for everyone -->
<button type="submit">Submit Form</button>

Sự thật phũ phàng: 96,3% trang web không vượt qua các bài kiểm tra accessibility cơ bản. Các công ty như Target (bị phạt 6 triệu USD), Domino’s (thua kiện tại Tòa Tối Cao) và Netflix (bị phạt 755.000 USD) đã phải học bài học này theo cách rất tốn kém.

ARIA - Tóm tắt cho lập trình viên bận rộn

ARIA = Accessible Rich Internet Applications

Đây là API giúp kết nối các thành phần tuỳ chỉnh của bạn với công nghệ hỗ trợ (trình đọc màn hình, v.v.).

Chỉ có 3 khái niệm cốt lõi:

  • Role – Nó là cái gì?
role="button"
  • Property – Tính chất của nó?
aria-required="true"
  • State – Trạng thái hiện tại?
aria-expanded="false"

Kiểm tra Accessibility nhanh trong 2 phút

1. Kiểm tra bằng Terminal

npm install -g @axe-core/cli
axe https://yoursite.com

2. Kiểm tra thủ công (hãy làm ngay)

  • Dùng phím Tab để di chuyển qua trang (không dùng chuột)
  • Bật chế độ tương phản cao (High Contrast Mode)
  • Phóng to trang lên 200%
  • Dùng VoiceOver (Mac: Cmd+F5) hoặc NVDA (Windows, miễn phí)

Nếu bất kỳ bước nào thất bại, trang của bạn đang gây khó khăn cho hàng triệu người dùng.

Mẫu ARIA thiết yếu (Sao chép – dán – sử dụng)

Phần tử tương tác tuỳ chỉnh

<!-- Don't reinvent the wheel -->
<button>Native Button</button> <!-- But if you must... -->
<div role="button" tabindex="0" aria-label="Close dialog" onKeyPress="handleEnterSpace(event)" onClick="handleClick()"> ×
</div> <script>
function handleEnterSpace(e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleClick(); }
}
</script>

Form Validation hữu ích

<!-- Before: Silent failures -->
<input type="email" required>
<span class="error hidden">Invalid email</span> <!-- After: Accessible feedback -->
<label for="email">Email Address</label>
<input id="email" type="email" aria-required="true" aria-invalid="false" aria-describedby="email-error">
<div id="email-error" role="alert" aria-live="assertive" class="error hidden"> Invalid email format
</div>

Dynamic Content Updates

<!-- Status container -->
<div id="status" role="status" aria-live="polite"></div> <script>
// This announces to screen readers
document.getElementById('status').textContent = 'Changes saved!'; // For urgent updates
document.getElementById('status').setAttribute('aria-live', 'assertive');
</script>

Thành phần điều hướng

<!-- Accessible dropdown -->
<nav> <button aria-expanded="false" aria-controls="nav-menu" aria-haspopup="true"> Menu </button> <ul id="nav-menu" hidden> <li><a href="/home">Home</a></li> <li><a href="/about">About</a></li> </ul>
</nav>

React + ARIA (Cách làm đúng)

import { useState, useRef, useEffect } from 'react'; function AccessibleModal({ isOpen, onClose, title, children }) { const modalRef = useRef(null); const previousFocus = useRef(null); useEffect(() => { if (isOpen) { previousFocus.current = document.activeElement; modalRef.current?.focus(); } else { previousFocus.current?.focus(); } }, [isOpen]); const handleKeyDown = (e) => { if (e.key === 'Escape') { onClose(); } }; if (!isOpen) return null; return ( <div className="modal-overlay" onClick={onClose} > <div ref={modalRef} role="dialog" aria-modal="true" aria-labelledby="modal-title" tabIndex={-1} onKeyDown={handleKeyDown} onClick={(e) => e.stopPropagation()} > <h2 id="modal-title">{title}</h2> {children} <button onClick={onClose}>Close</button> </div> </div> );
} // Usage
<AccessibleModal isOpen={showModal} onClose={() => setShowModal(false)} title="Confirm Action"
> <p>Are you sure you want to delete this item?</p>
</AccessibleModal>

Debug ARIA (Script cho Dev Tools)

Tìm input không có nhãn

console.log('Unlabeled inputs:', Array.from(document.querySelectorAll('input, textarea, select')) .filter(el => !el.labels?.length && !el.getAttribute('aria-label') && !el.getAttribute('aria-labelledby'))
);

Kiểm tra tabindex không hợp lý

console.log('Positive tabindex (avoid these):', Array.from(document.querySelectorAll('[tabindex]')) .filter(el => el.tabIndex > 0)
);

Tìm phần tử tương tác thiếu role

console.log('Interactive divs/spans missing roles:', Array.from(document.querySelectorAll('div[onclick], span[onclick]')) .filter(el => !el.getAttribute('role'))
);

7 Lỗi ARIA thường gặp

1. Role dư thừa

<!-- ❌ Redundant -->
<button role="button">Click me</button> <!-- ✅ Native semantics -->
<button>Click me</button>

2. Thiếu hỗ trợ bàn phím

<!-- ❌ Mouse-only -->
<div role="button" onclick="handleClick()">Submit</div> <!-- ✅ Keyboard accessible -->
<div role="button" tabindex="0" onclick="handleClick()" onkeydown="handleKeyPress(event)">Submit</div>

3. Quản lý focus sai

<!-- ❌ Focus disappears -->
<button onclick="this.remove()">Delete</button> <!-- ✅ Focus moves logically -->
<button onclick="deleteAndFocus()">Delete</button>

4. Lạm dụng aria-label

<!-- ❌ Unnecessary -->
<h1 aria-label="Page Title">Page Title</h1> <!-- ✅ Only when needed -->
<button aria-label="Close dialog">×</button>

Công cụ thiết yếu

Extensions nên cài

  • axe DevTools – Quét accessibility tự động
  • WAVE – Đánh giá trực quan
  • Lighthouse – Tích hợp sẵn trong Chrome DevTools

Trình đọc màn hình miễn phí

  • NVDA (Windows) – Tải tại nvaccess.org
  • VoiceOver (Mac) – Tích hợp sẵn, bật bằng Cmd+F5
  • TalkBack (Android) – Tích hợp sẵn

Các lệnh nhanh

Kiểm tra accessibility bằng Lighthouse

lighthouse https://yoursite.com --only-categories=accessibility

Kiểm tra độ tương phản màu (nếu đã cài node)

npx @adobe/leonardo-contrast-colors --bg "#ffffff" --colors "#0066cc"

Checklist kiểm tra trước khi Merge Pull Request

  • Tab navigation hoạt động không cần chuột
  • Có hiển thị focus rõ ràng
  • Trình đọc màn hình đọc nội dung chính xác
  • Màu sắc đạt tiêu chuẩn WCAG AA (4.5:1)
  • Lỗi form được thông báo
  • Nội dung động được thông báo
  • Thành phần tuỳ chỉnh có role phù hợp
  • Skip links hoạt động

Trải nghiệm của bạn?

Hãy để lại bình luận:

  • Bạn gặp khó khăn gì với accessibility?
  • Bạn tin dùng công cụ nào nhất?
  • Có câu chuyện kinh hoàng nào từ các cuộc audit accessibility?

Hãy cùng nhau xây dựng web dễ dùng cho mọi người, từng component một.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tài nguyên nghiên cứu sâu Html

1. Articles and standards. . HTML 5.

0 0 213

- vừa được xem lúc

Embedded Template in Go

Getting Start. Part of developing a web application usually revolves around working with HTML as user interface.

0 0 66

- vừa được xem lúc

Full Stack Developer Roadmap 2021

Cách để trở thành một Full Stack Web Developer trên thế giới hiện nay. Các công ty đang luôn săn đón những developer có nhiều kĩ năng để cung cấp cho họ sự linh hoạt trong các dự án.

0 0 54

- vừa được xem lúc

Những kiến thức hay về Gradient: Gradient đẹp nhất chỉ được tìm thấy ở ngoài thiên nhiên!

. Quen thuộc từ lâu với rất nhiều người, nền Gradient chỉ là những bức nền với 2 hay nhiều dải màu sắc được hòa trộn với nhau. Đơn giản là vậy, nhưng càng ngày Gradient càng phổ biến hơn trong thiết kế Website ngày nay.

0 0 306

- vừa được xem lúc

What Is Session Fixation?

Session Fixation là một kỹ thuật tấn công web. Kẻ tấn công lừa người dùng sử dụng session ID đặc biệt.

0 0 63

- vừa được xem lúc

Làm thế nào để Design của Website thu hút hơn?

Xin chào các bạn. Bởi thế, không phải bàn cãi, thiết kế giao diện vừa thu hút, vừa chuyên nghiệp và ấn tượng là một trong những yếu tố quan trọng nhất trong cả quá trình phát triển 1 website.

0 0 46