Xây dựng các ứng dụng Angular dễ tiếp cận hơn

1. Trước khi bắt đầu

Biểu trưng Angular màu đen

Hỗ trợ tiếp cận là một phần quan trọng trong quá trình phát triển web, đảm bảo rằng người dùng có thể nhận biết, hiểu, điều hướng và tương tác với các ứng dụng. Trên thực tế, cứ 4 người lớn ở Hoa Kỳ thì có 1 người khuyết tật ảnh hưởng đến các hoạt động chính trong cuộc sống của họ. Trên toàn thế giới, khoảng 15% dân số thế giới (tức hơn 1 tỷ người) mắc một dạng khuyết tật nào đó, trong đó khoảng 2 đến 4% gặp nhiều khó khăn.

Sau đây là một số tình trạng thường gặp ảnh hưởng đến khả năng sử dụng web của một người: mù hoặc thị lực kém, điếc hoặc suy giảm thính giác, kỹ năng vận động hạn chế, khuyết tật trí tuệ và mù màu. Đây chỉ là một danh sách chưa đầy đủ.

Trong khoá học này, a11y là từ viết tắt của khả năng hỗ trợ tiếp cận. Lưu ý rằng a theo sau là 11 ký tự và y.

Để xem phần giới thiệu chi tiết về các vấn đề và kỹ thuật thiết kế ứng dụng hỗ trợ tiếp cận, hãy xem phần Hỗ trợ tiếp cận.

Sản phẩm bạn sẽ tạo ra

  • Sử dụng các phương pháp hay nhất và kỹ thuật tích hợp để giải quyết các vấn đề thường gặp về khả năng hỗ trợ tiếp cận trên web trong một ứng dụng Angular Dumpling Shop minh hoạ
  • Đáp ứng tất cả các nguyên tắc hỗ trợ tiếp cận, WCAG 2.0 và ARIA 1.2, đồng thời vượt qua các quy trình kiểm tra khả năng hỗ trợ tiếp cận bằng axe và Lighthouse.

Trang web của cửa hàng Dumpling Time có giao diện màu hồng và đỏ Trang web của cửa hàng Dumpling Time có giao diện màu tím và xanh lục

Kiến thức bạn sẽ học được

Bạn sẽ tìm hiểu về 8 vấn đề thường gặp về khả năng tiếp cận trong các ứng dụng Angular ảnh hưởng đến người dùng, cách xác định và cách khắc phục các vấn đề đó. Cụ thể hơn, bạn:

  • Sử dụng Công cụ cho nhà phát triển Chrome, Lighthouse và axe để kiểm tra khả năng hỗ trợ tiếp cận của ứng dụng
  • Giải quyết các vấn đề thường gặp về ứng dụng trang đơn (SPA) bằng tiêu đề trang riêng biệt
  • Khắc phục các vấn đề về độ tương phản màu thấp cho người dùng có thị lực kém
  • Sử dụng HTML ngữ nghĩa để đảm bảo trình đọc màn hình điều hướng trang một cách chính xác
  • Sử dụng Angular Material và tách các chế độ điều khiển để đảm bảo trình đọc màn hình có thể truy cập vào tất cả chế độ điều khiển
  • Thêm tính năng hỗ trợ ARIA cho trình đọc màn hình
  • Nhập và sử dụng gói a11y CDK Angular
  • Sử dụng FocusTrap để điều hướng trình đọc màn hình của thành phần tuỳ chỉnh
  • Báo cáo thông báo bằng LiveAnnouncer của CDK
  • Phát hiện người dùng ở chế độ HighContrast và triển khai giao diện tương phản cao

Bạn cần có

2. Bắt đầu thiết lập

Lấy

Mọi thứ bạn cần cho dự án này đều nằm trong một kho lưu trữ GitHub. Để bắt đầu, hãy sao chép mã và mở mã đó trong môi trường phát triển mà bạn yêu thích.

Sao chép kho lưu trữ và phân phát ứng dụng

VSCode hoặc một IDE cục bộ là phương pháp nên dùng để thực hiện lớp học lập trình này.

  1. Mở một thẻ trình duyệt mới rồi truy cập vào https://github.com/googlecodelabs/angular-accessibility.
  2. Phân nhánh và sao chép kho lưu trữ, rồi cd angular-accessibility/ vào kho lưu trữ.
  3. Kiểm tra nhánh mã khởi đầu git checkout get-started.
  4. Mở mã trong VSCode hoặc IDE mà bạn muốn.
  5. Chạy npm install để cài đặt các phần phụ thuộc cần thiết để chạy máy chủ.
  6. Chạy ng serve để chạy máy chủ.
  7. Mở một thẻ trình duyệt đến http://localhost:4200.

3. Thiết lập đường cơ sở

Điểm xuất phát của bạn là gì?

Điểm xuất phát của bạn là một ứng dụng nhà hàng cơ bản được thiết kế cho lớp học lập trình này. Mã này đã được đơn giản hoá để minh hoạ các khái niệm trong lớp học lập trình này và có rất ít chức năng.

Trang web của cửa hàng Dumpling Time có giao diện màu tím và xanh lục

Khám phá bản minh hoạ

Để bắt đầu, hãy tìm hiểu 3 chức năng của ứng dụng:

  1. Sử dụng thanh điều hướng để xem các tuyến đường Cửa hàng của chúng tôi, Câu chuyện của chúng tôiTìm chúng tôi, đồng thời xem thông tin chi tiết về công ty sản xuất bánh bao.
  2. Thay đổi giao diện để bật/tắt chế độ sáng và tối.
  3. Tuỳ chỉnh nhân, số lượng và màu sắc của bánh bao trong đơn đặt hàng.
  4. Chọn Mua để ghi lại đơn đặt hàng tuỳ chỉnh của bạn trong bảng điều khiển.

Sử dụng Angular để giải quyết các vấn đề thường gặp về khả năng hỗ trợ tiếp cận trên web

Trong lớp học lập trình này, bạn sẽ tập trung vào khả năng hỗ trợ tiếp cận của các tính năng hiện có trong ứng dụng này. Bạn sẽ bắt đầu bằng cách xác định các vấn đề về khả năng hỗ trợ tiếp cận trong ứng dụng, sau đó chuyển 🛑 thành ✅ bằng cách triển khai một giải pháp.

Làm sao để biết cần khắc phục vấn đề gì?

Bắt đầu mỗi ví dụ bằng cách nhận biết vấn đề về khả năng hỗ trợ tiếp cận bằng cách kết hợp kiểm thử thủ công và tự động.

Trong trạng thái hiện tại của web, bạn bắt buộc phải kiểm thử khả năng hỗ trợ tiếp cận theo cách thủ công.

Bạn có các công cụ có thể xác định vấn đề về khả năng hỗ trợ tiếp cận, nhưng không có công cụ nào có thể chứng nhận rằng một ứng dụng có khả năng hỗ trợ tiếp cận đầy đủ. Kiểm thử thủ công đảm bảo rằng bạn kiểm thử nhiều khái niệm về khả năng tiếp cận, bao gồm cả thứ tự nội dung hợp lý và tính năng tương đương.

Kiểm thử thủ công

Để kiểm thử trợ năng theo cách thủ công trong khoá học này, bạn sẽ bật trình đọc màn hình tích hợp sẵn của máy tính và di chuyển trong ứng dụng bằng chế độ di chuyển bằng bàn phím. Để biết thêm thông tin, hãy xem bài viết Ngữ nghĩa và trình đọc màn hình.

Thực hành bằng cách bật trình đọc màn hình và điều hướng trên màn hình.

Bạn có thể sử dụng VoiceOver tích hợp sẵn trên macOS. Nhấp vào System Preferences (Tuỳ chọn ưu tiên của hệ thống) > Accessibility (Trợ năng) > VoiceOver > Enable VoiceOver (Bật VoiceOver) để bật tính năng này. Để bật/tắt VoiceOver, hãy nhấn nhanh Touch ID 3 lần trong khi giữ phím Command.

Trong khoá học này, bạn chủ yếu kiểm thử các vấn đề theo cách thủ công và sử dụng các công cụ tự động để hỗ trợ kiểm tra các tính năng cụ thể có thể tự động hoá.

Kiểm thử tự động

Bạn cũng có thể sử dụng một số công cụ phát triển để tự động hoá và kiểm tra ứng dụng của mình. Các công cụ này cho phép bạn kiểm tra những thứ như sự hiện diện của văn bản thay thế trên hình ảnh hoặc tỷ lệ tương phản của màu văn bản. Bạn có thể coi những công cụ này là linter; chúng có thể nhận ra rằng văn bản thay thế xuất hiện, nhưng bạn phải kiểm tra theo cách thủ công để đảm bảo nội dung hợp lý và mang lại giá trị.

Lighthouse và Công cụ cho nhà phát triển Chrome

  1. Mở Công cụ cho nhà phát triển Chrome.
  2. Chọn thẻ Lighthouse rồi chọn hộp đánh dấu Hỗ trợ tiếp cận.
  3. Nhấp vào Tạo báo cáo để chạy một quy trình kiểm tra Lighthouse về khả năng tiếp cận.

Ví dụ về thẻ Lighthouse có nút Tạo báo cáo trong thẻ Công cụ của Chrome cho nhà phát triển

Axe

  1. Cài đặt tiện ích axe DevTools. Bạn có thể phải khởi động lại trình duyệt để thấy tiện ích.
  2. Mở Công cụ cho nhà phát triển Chrome.
  3. Chọn thẻ axe DevTools rồi chọn Quét toàn bộ trang của tôi để chạy quy trình quét axe DevTools.

Tìm lỗi mã nguồn

Bạn có thể sử dụng các quy tắc ESLint của Angular để tìm lỗi mã nguồn cho mã của mình về các thuộc tính a11y có thể tự động hoá.

Trong eslint.json, hãy thêm những nội dung sau đây áp dụng cho khả năng hỗ trợ tiếp cận:

"@angular-eslint/template/accessibility-alt-text": 2,
"@angular-eslint/template/accessibility-elements-content": 2,
"@angular-eslint/template/accessibility-label-for": 2,
"@angular-eslint/template/no-positive-tabindex": 2,
"@angular-eslint/template/accessibility-table-scope": 2,
"@angular-eslint/template/accessibility-valid-aria": 2,
"@angular-eslint/template/click-events-have-key-events": 2,
"@angular-eslint/template/mouse-events-have-key-events": 2,
"@angular-eslint/template/no-autofocus": 2,
"@angular-eslint/template/no-distracting-elements": 2

Để biết thêm thông tin, hãy xem các quy tắc ESLint mới nhất trên GitHub.

Điểm xuất phát của bạn

Bằng các phương pháp kiểm thử mới, bạn có thể xác định các vấn đề sau trong ứng dụng bằng cách sử dụng các quy trình kiểm tra Lighthouse và axe, cũng như VoiceOver thủ công:

Báo cáo kiểm tra Lighthouse của Chrome DevTools với điểm số là 82

Kiểm tra khả năng hỗ trợ tiếp cận:

  • 🛑 Tất cả các trang đều có cùng tiêu đề trang
  • 🛑 Các phần tử phải có độ tương phản màu thích hợp
  • 🛑 HTML phải có thứ tự, tên và vai trò logic
  • 🛑 Trình đọc màn hình không chọn được các hộp đánh dấu lồng nhau
  • 🛑 Trình đọc màn hình không đọc các giá trị của thanh trượt
  • 🛑 Tiêu điểm của trình đọc màn hình trong bộ chọn màu sẽ thoát khỏi hộp thoại
  • 🛑 Không thông báo về các thay đổi, lỗi và thông báo
  • 🛑 Chế độ Tương phản cao chưa được bật

4. Xác định tiêu đề riêng biệt cho từng trang

Việc cung cấp tiêu đề trang độc đáo và ngắn gọn giúp người dùng sử dụng các dịch vụ hỗ trợ tiếp cận nhanh chóng nắm được nội dung và mục đích của một trang web. Tiêu đề trang là yếu tố quan trọng đối với người dùng khiếm thị vì đây là phần tử trang đầu tiên mà phần mềm đọc màn hình thông báo.

Angular là một ứng dụng một trang và do đó, phần lớn các hiệu ứng chuyển đổi (chẳng hạn như chuyển sang một trang mới) không liên quan đến việc tải lại trang. Cho đến gần đây, điều này có nghĩa là mỗi trang đều có tiêu đề trang giống hệt nhau và không mang lại giá trị nào cho việc tìm hiểu nội dung hoặc mục đích của trang.

Trong Angular phiên bản 14, Router đã thêm một phương thức tích hợp sẵn để xác định tiêu đề trang riêng biệt ngay từ đầu. Điều này giúp đơn giản hoá quy trình để đảm bảo nhà phát triển làm theo các phương pháp hay nhất về tiêu đề trang.

Khi kết thúc phần này, ứng dụng của bạn sẽ vượt qua quy trình kiểm tra sau:

  • 🛑 Tất cả các trang đều có cùng tiêu đề trang

Bạn có thể tìm thấy từng bước trong số này ở phần bình luận: TODO: #4. Define unique page titles.

Xác định vấn đề

Để xác định vấn đề này, hãy bật trình đọc màn hình rồi di chuyển giữa các thẻ Cửa hàng của chúng tôi, Câu chuyện của chúng tôiTìm chúng tôi để xem tiêu đề trang:

  1. Bật VoiceOver.
  2. Sử dụng chế độ điều hướng bằng thẻ để di chuyển giữa các trang.
  3. Xác minh tiêu đề trang luôn là a11y trong Angular.

Đây là một vấn đề vì tiêu đề trang của bạn phải là duy nhất để người dùng có thể nhanh chóng hiểu được nội dung của trang mà không cần phải điều hướng qua trang đó.

Trình duyệt Chrome có 3 thẻ đang mở với tiêu đề trang giống hệt nhau: "a11y in Angular"

Thêm tiêu đề trang có ý nghĩa

Nếu một trang hoặc khung hiển thị thay đổi, bạn cần quản lý tiêu đề trang một cách thích hợp. Để khắc phục vấn đề này, bạn có thể sử dụng thuộc tính Router.title tích hợp của Angular để xác định tiêu đề riêng biệt cho từng trang.

  1. Thêm một tiêu đề riêng biệt cho mỗi trong số 3 tuyến đường đã xác định:

src/app/app-routing.module.ts

const routes: Routes = [
  { path: 'shop', component: ShopComponent, title: 'Our Shop – a11y in Angular' },
  { path: 'about', component: AboutComponent, title: 'Our Story - a11y in Angular' },
  { path: 'locate', component: LocationComponent, title: 'Find Us - a11y in Angular' },
  { path: '',   redirectTo: '/shop', pathMatch: 'full' },
  { path: '**', component: ShopComponent },
];

Thao tác này sẽ tự động nhập và sử dụng Router's Title Service ở chế độ nền để quản lý việc thay đổi tiêu đề trang trên thanh điều hướng cho phù hợp với thuộc tính tiêu đề được xác định trong các tuyến đường của chúng tôi. Bạn cũng có thể quản lý các tiêu đề trang phức tạp hơn bằng cách sử dụng TitleStrategy tuỳ chỉnh.

Xác minh thay đổi

Bật lại trình đọc màn hình rồi xác minh các thay đổi. Giờ đây, các trang sẽ có tiêu đề riêng biệt!

Trình duyệt Chrome có 3 thẻ đang mở với tiêu đề trang riêng biệt: "Our Shop - a11y in Angular", "Our Story - a11y in Angular", "Find Us - a11y in Angular"

Kiểm tra khả năng hỗ trợ tiếp cận:

  • Tất cả các trang đều có tiêu đề trang riêng biệt
  • 🛑 Các phần tử phải có độ tương phản màu thích hợp
  • 🛑 HTML phải có thứ tự, tên và vai trò logic
  • 🛑 Trình đọc màn hình không chọn được các hộp đánh dấu lồng nhau
  • 🛑 Trình đọc màn hình không đọc các giá trị của thanh trượt
  • 🛑 Tiêu điểm của trình đọc màn hình trong bộ chọn màu sẽ thoát khỏi hộp thoại
  • 🛑 Không thông báo về các thay đổi, lỗi và thông báo
  • 🛑 Chế độ Tương phản cao chưa được bật

5. Đảm bảo độ tương phản màu sắc phù hợp

Thiết kế của bạn có thể trông rất bắt mắt, nhưng sẽ không hiệu quả nếu những người khiếm thị như người mù màu không đọc được nội dung của bạn. Nguyên tắc về khả năng tiếp cận đối với nội dung web (WCAG 2.0) xác định một loạt tỷ lệ tương phản màu, đảm bảo rằng nội dung có thể tiếp cận được. Trong Angular và trên web, bạn có thể xác định bảng màu để đảm bảo các thành phần của bạn đáp ứng những tiêu chuẩn này và người dùng bị suy giảm thị lực và mù màu có thể nhìn thấy.

Khi kết thúc phần này, ứng dụng của bạn sẽ vượt qua quy trình kiểm tra sau:

  • 🛑 Các phần tử phải có độ tương phản màu thích hợp

Bạn có thể tìm thấy từng bước trong số này ở phần bình luận: TODO: #5. Ensure adequate color contrast.

Sử dụng Công cụ cho nhà phát triển Chrome để xác định các vấn đề về độ tương phản thấp

Để xác định vấn đề này, hãy sử dụng Công cụ cho nhà phát triển Chrome để kiểm tra các phần tử trong ứng dụng của bạn.

  1. Sử dụng công cụ kiểm tra để xem các nút biểu tượng trình đơn. Bạn có thể thấy độ tương phản là 1,85, thấp hơn nhiều so với yêu cầu của WCAG.

Chrome DevTools kiểm tra phần tử của nút Trang chủ có độ tương phản thấp

  1. Chạy quy trình Kiểm tra khả năng tiếp cận trong Lighthouse hoặc quy trình quét của axe để xem những vấn đề về tỷ lệ tương phản này.

Kết quả kiểm tra Lighthouse của Chrome DevTools có lỗi: "Màu nền trước và nền sau không có đủ tỷ lệ tương phản"

Thay đổi màu giao diện Material

Bảng phối màu thành phần được xác định trong giao diện Material tuỳ chỉnh. Bạn cập nhật giá trị của giao diện để đáp ứng các nguyên tắc về tỷ lệ tương phản màu.

Cập nhật giao diện Material để sử dụng màu văn bản tối hơn, tăng tỷ lệ tương phản của các biểu tượng:

src/styles.scss

$light-primary: mat.define-palette(mat.$pink-palette, $default: A100, $lighter: 100, $text: 900);

Bạn cũng có thể sử dụng công cụ hỗ trợ tiếp cận tích hợp của Công cụ cho nhà phát triển Chrome để tìm màu đáp ứng các tiêu chuẩn hoặc cập nhật các giá trị màu riêng lẻ trong Sass.

Xác minh thay đổi

Kiểm tra lại các phần tử và xác minh các thay đổi, giao diện của bạn hiện phải có tỷ lệ tương phản màu sắc phù hợp!

Chrome DevTools kiểm tra phần tử của nút Trang chủ có độ tương phản đủ

Kiểm tra khả năng hỗ trợ tiếp cận

  • Tất cả các trang đều có tiêu đề trang riêng biệt
  • Màu sắc có tỷ lệ tương phản vừa đủ
  • 🛑 HTML phải có thứ tự, tên và vai trò hợp lý
  • 🛑 Trình đọc màn hình không chọn được các hộp đánh dấu lồng nhau
  • 🛑 Trình đọc màn hình không đọc các giá trị của thanh trượt
  • 🛑 Tiêu điểm của trình đọc màn hình trong bộ chọn màu sẽ thoát khỏi hộp thoại
  • 🛑 Không thông báo về các thay đổi, lỗi và thông báo
  • 🛑 Chế độ Tương phản cao chưa được bật

6. Sử dụng HTML có ngữ nghĩa

Các phần tử HTML gốc nắm bắt một số mẫu tương tác tiêu chuẩn quan trọng đối với khả năng tiếp cận. Mặc dù bạn có thể tạo kiểu cho đoạn văn dưới dạng một khoảng và tạo kiểu cho div dưới dạng một nút, nhưng phần tử HTML ngữ nghĩa đảm bảo rằng trình đọc màn hình và chế độ điều hướng bằng bàn phím hiểu được các hoạt động tương tác và chế độ kiểm soát của HTML.

Khi tạo các thành phần Angular, bạn nên trực tiếp sử dụng lại các phần tử gốc này khi có thể, thay vì triển khai lại các hành vi được hỗ trợ tốt. Điều này đảm bảo trang có cấu trúc nội dung tốt và luồng nội dung tự nhiên, đồng thời thẻ nằm theo thứ tự hợp lý để hỗ trợ người dùng điều hướng trang web một cách hiệu quả bằng bàn phím.

Khi kết thúc phần này, ứng dụng của bạn sẽ vượt qua quy trình kiểm tra sau:

  • 🛑 HTML phải có thứ tự, tên và vai trò logic

Bạn có thể tìm thấy từng bước trong số này ở phần bình luận: TODO: #6. Use Semantic HTML.

Xác định vấn đề

  1. Bật VoiceOver.
  2. Sử dụng chế độ di chuyển bằng phím tab để nhấp vào thẻ Câu chuyện của chúng tôi.
  3. Lưu ý rằng thứ tự thẻ không tuần tự.
  4. Nhấp vào Purchas.
  5. Lưu ý rằng nút này không được nhận dạng là một nút.

Kết quả kiểm tra Lighthouse của Chrome DevTools có lỗi: Các phần tử tiêu đề không theo thứ tự giảm dần tuần tự. Các tiêu đề được sắp xếp đúng cách và không bỏ qua cấp độ sẽ truyền tải cấu trúc ngữ nghĩa của trang, giúp người dùng dễ dàng điều hướng và hiểu được nội dung khi sử dụng công nghệ hỗ trợ. Tìm hiểu thêm.

Thay đổi <div> thành <button>

Thay thế <div> tuỳ chỉnh bằng một nút Material:

src/app/shop/shop.component.html

<button mat-flat-button 
  color="primary" 
  class="purchase-button"
  (click)="fauxPurchase()">
  Purchase
</button>

Sử dụng các phần tử tiêu đề theo trình tự

Sắp xếp lại văn bản để sử dụng HTML có ngữ nghĩa và áp dụng kiểu bằng kiểu chữ Angular Material:

src/app/about/about.component.html

<h2>Who are we?</h2>
<p class="mat-subheading-2">Have you ever thought, "wow, I love dumplings"?</p>
<p class="right mat-subheading-1">Who hasn't.</p>
<p class="center mat-subheading-1">We took it one step further and created Dumpling Dumpling,</p> 
<p class="center mat-subheading-1">double the dumpling, double the fun.</p>
<div class="spacer"></div>
<h2>How are we different?</h2>
<p class="mat-subheading-2">Handmade in San Francisco, California, we craft fully customizable dumplings. Glitter? Rainbows? Vegan? We do it all.</p>
<p class="right mat-subheading-2">This shop is concept only.</p>

Xác minh thay đổi

Bật lại trình đọc màn hình rồi xác minh các thay đổi. Giờ đây, VoiceOver sẽ nhận dạng nút và đọc văn bản theo một thứ tự hợp lý!

Kiểm tra khả năng hỗ trợ tiếp cận:

  • Tất cả các trang đều có tiêu đề trang riêng biệt
  • Màu sắc có tỷ lệ tương phản vừa đủ
  • HTML ngữ nghĩa đảm bảo tương tác hợp lý
  • 🛑 Trình đọc màn hình không chọn được các hộp đánh dấu lồng nhau
  • 🛑 Trình đọc màn hình không đọc các giá trị của thanh trượt
  • 🛑 Tiêu điểm của trình đọc màn hình trong bộ chọn màu sẽ thoát khỏi hộp thoại
  • 🛑 Không thông báo về các thay đổi, lỗi và thông báo
  • 🛑 Chế độ Tương phản cao chưa được bật

7. Tạo các chế độ kiểm soát có thể chọn bằng Angular Material

Một mẫu tương tác phức tạp đối với các dịch vụ hỗ trợ tiếp cận là các thành phần điều khiển lồng nhau. Hãy nghĩ đến các mục con trong trình đơn hoặc hộp đánh dấu lồng nhau. Làm cách nào để cho người dùng biết rằng họ có thể chọn một nhóm nhỏ các lựa chọn hoặc chuyển đến một mục trong trình đơn chính?

Trong Angular, hãy đơn giản hoá các trình đơn và chế độ điều khiển để tạo các thành phần có thể điều hướng bằng cách đơn giản hoá các chế độ điều khiển nhiều nhất có thể. Trong ví dụ này, bạn sẽ dùng hộp danh sách của Angular Material để tạo một ví dụ về mẫu tương tác này.

Khi kết thúc phần này, ứng dụng của bạn sẽ vượt qua quy trình kiểm tra sau:

  • 🛑 Trình đọc màn hình không chọn được các hộp đánh dấu lồng nhau

Bạn có thể tìm thấy từng bước trong số này ở phần bình luận: TODO: #7. Create selectable controls with Angular Material.

Xác định vấn đề

Để xác định vấn đề này, chúng ta sẽ bật trình đọc màn hình và cố gắng chọn một hộp đánh dấu lồng nhau.

  1. Bật VoiceOver.
  2. Chọn các hương vị nhân khác nhau.
  3. Lưu ý rằng các hộp đánh dấu chính không chỉ định các hộp đánh dấu con khi VoiceOver đọc. Làm cách nào để biết hộp đánh dấu Thuần chay hiện không được chọn sau khi bạn bỏ chọn hộp đánh dấu Cải thìa?

Trình đơn hộp đánh dấu nhân bánh với các lựa chọn: Nhân bánh thuần chay gồm cải thìa, đậu phụ và nấm hương, thịt gà, thịt giả

Hỗ trợ tiếp cận trong Angular Material

Bạn thay thế hộp đánh dấu ngữ nghĩa bằng hộp đánh dấu Angular Material. Hộp này có kiến thức tích hợp về mẫu tương tác này. Bạn cần lưu ý rằng việc thay thế các thành phần bằng Material không đảm bảo khả năng hỗ trợ tiếp cận. Giống như mọi thành phần khác, bạn cần kiểm thử theo cách thủ công vì có rất nhiều cách để triển khai Material theo cách không thể truy cập.

Thay thế hộp đánh dấu bằng hộp đánh dấu Material

  1. Trước tiên, hãy thêm danh sách nhân mới và một biến để lưu trữ các hương vị nhân đã chọn:

src/app/shop/shop.component.ts

@Component(...)
export class ShopComponent implements OnInit {
  fillings: string[] = ['Bok Choy & Chili Crunch', 'Tofu & Mushroom', 'Chicken & Ginger', 'Impossible Meat & Spinach'];
  selectedFillings: string[] = [];

  fauxPurchase(): void {
    let flavor = '';
    this.selectedFillings.forEach(filling => {
      flavor = flavor + " " + filling
    })
  }
}
  1. Thêm một <mat-selection-list> để thay thế nhóm hộp đánh dấu HTML lộn xộn này:

src/app/shop/shop.component.html

<mat-selection-list [(ngModel)]="selectedFillings" 
  aria-label="Dumpling fillings">
  <mat-list-option *ngFor="let flavor of fillings" 
    [value]="flavor" 
    color="primary">
    {{ flavor }}
  </mat-list-option>
</mat-selection-list>

Các nhận xét TODO cũng cho biết nơi bạn có thể xoá một số Sass không dùng đến trong src/app/shop/shop.component.scss để dọn dẹp kiểu.

Xác minh thay đổi

Bật lại trình đọc màn hình rồi xác minh các thay đổi. Giờ đây, bạn có thể chọn hộp đánh dấu và điều hướng một cách trực quan hơn bằng trình đọc màn hình!

Hộp kiểm Fillings (Nhân) có các mục: Fillings Bok Choy & Chili Crunch Tofu & Mushroom Chicken & Ginger Impossible Meat & Spinach Quantity (Nhân cải thìa, đậu phụ giòn cay, gà nấm, thịt thực vật gừng và rau chân vịt)

Kiểm tra khả năng hỗ trợ tiếp cận:

  • Tất cả các trang đều có tiêu đề trang riêng biệt
  • Màu sắc có tỷ lệ tương phản vừa đủ
  • HTML ngữ nghĩa đảm bảo tương tác hợp lý
  • Trình đọc màn hình có thể truy cập vào tất cả các chế độ kiểm soát
  • 🛑 Trình đọc màn hình không đọc các giá trị của thanh trượt
  • 🛑 Tiêu điểm của trình đọc màn hình trong bộ chọn màu sẽ thoát khỏi hộp thoại
  • 🛑 Không thông báo về các thay đổi, lỗi và thông báo
  • 🛑 Chế độ Tương phản cao chưa được bật

8. Cung cấp nhãn điều khiển bằng ARIA

Bạn đã sửa đổi HTML ngữ nghĩa và các thành phần Material của ứng dụng Angular, nhưng một số thành phần yêu cầu các thuộc tính cụ thể để trình đọc màn hình có thể điều hướng đầy đủ.

Quy cách về Ứng dụng Internet phong phú có thể truy cập của Sáng kiến về khả năng tiếp cận web (WAI-ARIA hoặc ARIA) giúp giải quyết những vấn đề không thể quản lý bằng HTML gốc. Bạn có thể chỉ định các thuộc tính sửa đổi cách một phần tử được dịch sang cây hỗ trợ tiếp cận.

Khi kết thúc phần này, ứng dụng của bạn sẽ vượt qua quy trình kiểm tra sau:

  • 🛑 Trình đọc màn hình không đọc các giá trị của thanh trượt

Bạn có thể tìm thấy từng bước trong số này ở phần bình luận: TODO: #8. Provide control labels with ARIA.

Xác định vấn đề

Để xác định vấn đề này, hãy bật trình đọc màn hình rồi di chuyển thanh trượt:

  1. Bật VoiceOver.
  2. Chuyển đến thanh trượt số lượng và thay đổi giá trị.
  3. Lưu ý rằng nhãn giá trị bị thiếu.

Kết quả kiểm tra Lighthouse của Chrome DevTools có lỗi:  Tên các trường nhập của ARIA ở trạng thái không thể tiếp cận Khi một trường nhập dữ liệu không có tên thành phần hỗ trợ tiếp cận, thì trình đọc màn hình sẽ gọi trường đó bằng tên gọi chung, khiến người dùng trình đọc màn hình không dùng được trường này. Tìm hiểu thêm.

Sử dụng thuộc tính ARIA

Điều khiển nhãn bằng cách sử dụng aria-label đến <mat-slider>:

src/app/shop/shop.component.html

<mat-slider
  aria-label="Dumpling order quantity slider"
  id="quantity"
  name="quantity"
  color="primary"
  class="quantity-slider"
  [max]="13"
  [min]="1"
  [step]="1"
  [tickInterval]="1"
  thumbLabel
  [(ngModel)]="quantity">
</mat-slider>

Xác minh thay đổi

Bật lại trình đọc màn hình rồi xác minh các thay đổi. Bây giờ, bạn có thể di chuyển thanh trượt!

Kiểm tra Lighthouse của Chrome DevTools với kết quả kiểm tra đạt yêu cầu đối với các chế độ kiểm soát ARIA của trình đọc màn hình.

Kiểm tra khả năng hỗ trợ tiếp cận:

  • Tất cả các trang đều có tiêu đề trang riêng biệt
  • Màu sắc có tỷ lệ tương phản vừa đủ
  • HTML ngữ nghĩa đảm bảo tương tác hợp lý
  • Trình đọc màn hình có thể truy cập vào tất cả các chế độ kiểm soát
  • Thanh trượt sử dụng thuộc tính ARIA để cung cấp nhãn
  • 🛑 Tiêu điểm của trình đọc màn hình trong bộ chọn màu sẽ thoát khỏi hộp thoại
  • 🛑 Không thông báo về các thay đổi, lỗi và thông báo
  • 🛑 Chế độ Tương phản cao chưa được bật

9. Thêm sức mạnh của @angular/cdk/a11y

Cho đến nay, bạn đã dựa vào các công cụ Angular tích hợp để khắc phục các vấn đề thường gặp về khả năng tiếp cận. Bây giờ, hãy xem mô-đun a11y của CDK và cách mô-đun này có thể giúp chúng ta giải quyết các vấn đề phức tạp hơn và dành riêng cho Angular.

Khi kết thúc phần này, bạn sẽ tiếp tục khoá học này bằng công cụ mô-đun a11y của Angular.

Bạn có thể tìm thấy các bước này bên dưới bình luận: TODO: #9. Add the power of @angular/cdk/a11y.

Nhập mô-đun

Thêm mô-đun vào ứng dụng của bạn:

src/app/app.module.ts

import { A11yModule } from '@angular/cdk/a11y';

@NgModule({
  declarations: [...],
  imports: [
    A11yModule
  ],
  providers: [...],
  bootstrap: [...]
})

'@angular/cdk/a11y' làm gì?

Mô-đun a11y cung cấp một số công cụ để cải thiện khả năng tiếp cận và đặc biệt hữu ích cho các tác giả thành phần.

Trong các phần sau, bạn sẽ thêm 3 dịch vụ phổ biến: FocusTrap, LiveAnnouncer và HighContrast.

Để biết thêm thông tin về tất cả các dịch vụ khác mà @angular/cdk/a11y cung cấp, hãy xem phần Hỗ trợ tiếp cận.

10. Kiểm soát tiêu điểm bằng FocusTrap

Khi một hộp thoại hoặc cửa sổ phương thức mở ra, người dùng sẽ chỉ tương tác bên trong hộp thoại hoặc cửa sổ đó. Việc cho phép tiêu điểm thoát ra ngoài hộp thoại sẽ trộn lẫn các bối cảnh và tạo ra trạng thái mà người dùng không biết họ đang ở đâu trên trang.

Trong Angular, chỉ thị cdkTrapFocus sẽ giữ tiêu điểm phím tab- trong một phần tử. Bạn có thể dùng thuộc tính này để tạo trải nghiệm hỗ trợ tiếp cận cho các thành phần như hộp thoại phương thức, nơi bạn phải giới hạn tiêu điểm.

Khi kết thúc phần này, ứng dụng của bạn sẽ vượt qua quy trình kiểm tra sau:

  • 🛑 Tiêu điểm của trình đọc màn hình trong bộ chọn màu sẽ thoát khỏi hộp thoại

Bạn có thể xem các bước này bên dưới phần bình luận: TODO: #10. Control focus with FocusTrap.

Xác định vấn đề

Để xác định vấn đề này, hãy bật trình đọc màn hình rồi mở hộp thoại bộ chọn màu.

  1. Bật VoiceOver.
  2. Sử dụng chế độ điều hướng bằng phím tab để thay đổi màu.
  3. Kiểm tra để xem thứ tự lấy nét trực quan và tính năng chặn lấy nét trong bộ chọn màu.

Trang web của cửa hàng Dumpling Time có giao diện màu tím và xanh lục, với hộp thoại mở ra để chọn màu vỏ bánh

Thêm FocusTrap

Bạn có thể dùng cdkFocusTrap để bẫy và kiểm soát thứ tự tiêu điểm trong các thành phần tuỳ chỉnh. Việc sử dụng mat-dialog-content là đủ để giải quyết hầu hết các vấn đề bằng cách giữ tiêu điểm trong một hộp thoại. Thêm thuộc tính cdkFocusInitial để xác định vùng tiêu điểm ban đầu trên màu của lớp vỏ bánh <mat-selection-list> trong hộp thoại bộ chọn màu.

src/app/shop/color-picker/color-picker-dialog/color-picker-dialog.component.html

<mat-selection-list #colors aria-label="Dumpling wrapper color" multiple="false" cdkFocusInitial>
  ...
</mat-selection-list>

Xác minh thay đổi

Bật lại trình đọc màn hình rồi xác minh các thay đổi. Giờ đây, tiêu điểm ban đầu được đặt trên Thay đổi màu trong hộp thoại!

Kiểm tra khả năng hỗ trợ tiếp cận:

  • Tất cả các trang đều có tiêu đề trang riêng biệt
  • Màu sắc có tỷ lệ tương phản vừa đủ
  • HTML ngữ nghĩa đảm bảo tương tác hợp lý
  • Trình đọc màn hình có thể truy cập vào tất cả các chế độ kiểm soát
  • Thanh trượt sử dụng thuộc tính ARIA để cung cấp nhãn
  • Công cụ chọn màu có tính năng bắt tiêu điểm chính xác
  • 🛑 Không thông báo về các thay đổi, lỗi và thông báo
  • 🛑 Chế độ Tương phản cao chưa được bật

11. Thông báo thay đổi bằng LiveAnnouncer

Trình đọc màn hình cần được thông báo khi có nội dung trên trang thay đổi. Hãy tưởng tượng bạn đang cố gắng gửi biểu mẫu hoặc hoàn tất giao dịch mua nhưng không biết rằng đã xảy ra lỗi khiến bạn không gửi được biểu mẫu. Thật là phiền toái!

LiveAnnouncer được dùng để thông báo các thông điệp cho người dùng trình đọc màn hình bằng cách sử dụng một vùng aria-live để đảm bảo trình đọc màn hình được thông báo về các thông báo và nội dung thay đổi trực tiếp trên trang. Để biết thêm thông tin về các vùng aria-live, hãy xem WAI-ARIA của W3C. Trong Angular, việc gọi LiveAnnouncer dưới dạng một dịch vụ là giải pháp dễ kiểm thử hơn so với các thuộc tính aria-live.

Khi kết thúc phần này, ứng dụng của bạn sẽ vượt qua quy trình kiểm tra sau:

  • 🛑 Không thông báo về các thay đổi, lỗi và thông báo

Bạn có thể xem các bước này bên dưới phần bình luận: TODO: #11. Announce changes with LiveAnnouncer.

Xác định vấn đề

Để xác định vấn đề này, hãy bật trình đọc màn hình rồi chọn Mua mà không điền vào các trường trong biểu mẫu:

  1. Bật VoiceOver.
  2. Sử dụng chế độ điều hướng bằng thẻ để thay đổi màu sắc và thực hiện giao dịch mua giả.
  3. Xin lưu ý rằng không có dấu hiệu nào cho biết màu đã chọn khi thoát khỏi hộp thoại và giao dịch mua chưa được đọc.

Trang web của cửa hàng Dumpling Time có giao diện màu hồng và đỏ, với hộp thoại mở ra để chọn màu của vỏ bánh

Thêm LiveAnnouncer vào mã của bạn

Thêm LiveAnnouncer và thông báo cả lựa chọn màu sắc lẫn giao dịch mua giả dưới dạng một chuỗi. Trong quá trình triển khai thực tế, thông tin này có thể được đọc khi bạn chuyển đến một hệ thống thanh toán của bên thứ ba hoặc khi có lỗi về biểu mẫu.

  1. Thêm thông báo khi chọn một màu:

src/app/shop/color-picker/color-picker-dialog/color-picker-dialog.component.ts

import { LiveAnnouncer } from '@angular/cdk/a11y';

@Component(...)
export class ColorPickerDialogComponent implements OnInit {
  constructor(
    public dialogRef: MatDialogRef<ColorPickerDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: ColorDialogData,
    private liveAnnouncer: LiveAnnouncer) { }

  public changeColor(color: string): void {
    this.liveAnnouncer.announce(`Select color: ${color}`);
    this.dialogRef.close();
  }
}
  1. Thêm thông báo khi có giao dịch mua hàng giả:

src/app/shop/shop.component.ts

import { LiveAnnouncer } from '@angular/cdk/a11y';

@Component(...)
export class ShopComponent implements OnInit {

  constructor(private liveAnnouncer: LiveAnnouncer) { }

  fauxPurchase(): void {
    let flavor = '...';
    const fakePurchase = `Purchase ${this.quantity} ${flavor}dumplings in the color ${this.color}!`;

    this.liveAnnouncer.announce(fakePurchase);
  }
}

Xác minh thay đổi

Bật lại trình đọc màn hình rồi xác minh các thay đổi. Giờ đây, bạn sẽ nhận được thông báo về các lỗi!

Kiểm tra khả năng hỗ trợ tiếp cận:

  • Tất cả các trang đều có tiêu đề trang riêng biệt
  • Màu sắc có tỷ lệ tương phản vừa đủ
  • HTML ngữ nghĩa đảm bảo tương tác hợp lý
  • Trình đọc màn hình có thể truy cập vào tất cả các chế độ kiểm soát
  • Thanh trượt sử dụng thuộc tính ARIA để cung cấp nhãn
  • Công cụ chọn màu có tính năng bắt tiêu điểm chính xác
  • Thông báo về các thay đổi, lỗi và thông báo
  • 🛑 Chế độ Tương phản cao chưa được bật

12. Bật chế độ HighContrast

Microsoft Windows hỗ trợ một tính năng hỗ trợ tiếp cận có tên là Chế độ tương phản cao. Chế độ này thay đổi giao diện của tất cả ứng dụng (kể cả ứng dụng web) để tăng đáng kể độ tương phản. Trong Angular, bạn muốn tôn trọng lựa chọn ưu tiên của người dùng trong ứng dụng của mình.

HighContrastModeDetector cho phép bạn xác định xem trình duyệt hiện có ở trong môi trường có chế độ tương phản cao hay không.

Internet Explorer, Microsoft Edge và Firefox đều hỗ trợ chế độ này. Google Chrome không hỗ trợ Chế độ tương phản cao của Windows. Dịch vụ này không phát hiện chế độ tương phản cao do tiện ích trình duyệt Chrome High Contrast thêm vào.

Khi kết thúc phần này, ứng dụng của bạn sẽ vượt qua quy trình kiểm tra sau:

  • 🛑 Chế độ Tương phản cao chưa được bật

Bạn có thể xem các bước này bên dưới phần bình luận: TODO: #12. Enable HighContrast mode.

Xác định vấn đề

Để xác định vấn đề này, hãy mở ứng dụng của bạn trong Internet Explorer, Microsoft Edge hoặc Firefox, bật Chế độ tương phản cao và quan sát xem có thay đổi nào không:

  1. Mở ứng dụng trong Internet Explorer, Microsoft Edge hoặc Firefox.
  2. Bật Chế độ tương phản cao.
  3. Lưu ý rằng ứng dụng không thay đổi.

Thêm chế độ hỗ trợ cho chế độ tương phản cao

Trong styles.scss, hãy sử dụng mixin cdk-high-contrast có trong @angular/cdk/a11y để thêm đường viền vào các nút ở Chế độ tương phản cao:

src/app/shop/shop.component.scss

@use '@angular/cdk';

.purchase-button {
    border-radius: 5px;
    background-color: mat.get-color-from-palette(mat.$pink-palette, A100);

    @include cdk-high-contrast {
      outline: solid 1px;
      background-color: mat.get-color-from-palette(mat.$pink-palette, 50);
    }
}

:host-context(.dark-theme) {
  .purchase-button {
    background-color: mat.get-color-from-palette(mat.$light-green-palette, A100);

    @include cdk-high-contrast {
      outline: solid 1px;
      background-color: mat.get-color-from-palette(mat.$light-green-palette, 50);
    }
  }
}

Xác minh thay đổi

Làm mới ứng dụng và xác minh các thay đổi. Bạn đã thêm một đường viền vào nút ở Chế độ tương phản cao!

Trang web của cửa hàng Dumpling Time có giao diện màu đỏ và hồng, Chế độ tương phản cao đang bật và nút mua hàng hiện được lấy tiêu điểm mạnh bằng đường viền màu đỏ dày Trang web của cửa hàng Dumpling Time có giao diện màu xanh dương và xanh lục, Chế độ tương phản cao đang bật và nút mua hàng hiện được lấy nét mạnh bằng đường viền màu xanh dương dày

Kiểm tra khả năng hỗ trợ tiếp cận:

  • Tất cả các trang đều có tiêu đề trang riêng biệt
  • Màu sắc có tỷ lệ tương phản vừa đủ
  • HTML ngữ nghĩa đảm bảo tương tác hợp lý
  • Trình đọc màn hình có thể truy cập vào tất cả các chế độ kiểm soát
  • Thanh trượt sử dụng thuộc tính ARIA để cung cấp nhãn
  • Công cụ chọn màu có tính năng bắt tiêu điểm chính xác
  • Thông báo về các thay đổi, lỗi và thông báo
  • Chế độ tương phản cao đang bật

13. Xin chúc mừng!

Xin chúc mừng! Bạn đã giải quyết các vấn đề thường gặp về khả năng hỗ trợ tiếp cận trên web trong ứng dụng Angular của mình! 🎉

Để xem tất cả các giải pháp, hãy xem nhánh main.

Trang web của cửa hàng Dumpling Time có giao diện màu đỏ và hồng cho thấy tất cả các thay đổi được thực hiện trong lớp học lập trình này Trang web của cửa hàng Dumpling Time có giao diện màu xanh dương và xanh lục cho thấy tất cả các thay đổi được thực hiện trong lớp học lập trình này Bài kiểm tra Lighthouse của Chrome DevTools với điểm số 100/100

Giờ đây, bạn đã biết các bước quan trọng cần thiết để giải quyết 8 lỗi thường gặp về khả năng tiếp cận trong ứng dụng Angular.

Tìm hiểu thêm

Hãy xem các lớp học lập trình sau:

Đọc các tài liệu sau: