Hộp thoại modal đóng vai trò quan trọng trong việc hiển thị thông tin nổi bật và thúc đẩy người dùng tương tác. Bài viết này sẽ hướng dẫn bạn cách xây dựng hộp thoại modal dễ tiếp cận, đảm bảo mọi người dùng, kể cả những người sử dụng công nghệ hỗ trợ, đều có thể sử dụng được.
Khi nào nên sử dụng hộp thoại Modal?
Trong quá trình phát triển web, chúng ta thường sử dụng hộp thoại modal hoặc popup để hiển thị thông tin quan trọng hoặc yêu cầu người dùng thực hiện hành động. Khác với các cửa sổ pop-up thông thường có thể được mở trong cửa sổ hoặc tab mới, các hộp thoại modal giữ người dùng ở lại trên cùng một trang bằng cách phủ lên nội dung hiện có. Điều này đảm bảo người dùng vẫn tập trung vào nhiệm vụ đang thực hiện. Hộp thoại modal rất phổ biến và đôi khi là bắt buộc.
Tuy nhiên, nếu không được triển khai chính xác, chúng có thể trở thành rào cản đáng kể đối với người dùng. Việc đảm bảo các hộp thoại modal có thể truy cập được đồng nghĩa với việc mọi người, bao gồm cả những người sử dụng công nghệ hỗ trợ, đều có thể sử dụng được. Trong bài viết này, chúng ta sẽ cùng nhau xây dựng một hộp thoại modal và tuân thủ các nguyên tắc để giúp nó dễ tiếp cận hơn.
Việc sử dụng hộp thoại modal hiệu quả đòi hỏi phải xem xét cẩn thận trải nghiệm của người dùng. Dưới đây là một số hướng dẫn để giúp bạn quyết định xem có nên sử dụng hộp thoại modal hay không:
- Bạn nên sử dụng hộp thoại modal khi người dùng cần đưa ra quyết định quan trọng, chẳng hạn như xác nhận hành động có khả năng gây hại (ví dụ: xóa một mục) hoặc đồng ý với các điều khoản và điều kiện.
- Bạn có thể sử dụng hộp thoại modal khi một tác vụ yêu cầu người dùng phải tập trung hoàn toàn và không phụ thuộc vào thông tin từ phần còn lại của trang (ví dụ: điền vào biểu mẫu hoặc hoàn tất quy trình thanh toán).
- Bạn có thể sử dụng hộp thoại modal để hiển thị thông tin tạm thời hoặc thoáng qua không cần hiển thị vĩnh viễn trên trang (ví dụ: cảnh báo, thông báo hoặc tin nhắn ngắn gọn).
- Bạn nên tránh sử dụng hộp thoại modal cho các tác vụ yêu cầu tương tác hoặc nhập liệu nhiều, chẳng hạn như biểu mẫu dài hoặc quy trình công việc phức tạp. Những điều này có thể gây khó chịu trong hộp thoại modal do không gian hạn chế và các hạn chế về điều hướng.
- Bạn nên tránh sử dụng hộp thoại modal cho các hành động mà người dùng sẽ cần thực hiện thường xuyên, vì điều này có thể trở nên lặp đi lặp lại và gây khó chịu. Các tùy chọn nội tuyến hoặc chú giải công cụ có thể tốt hơn cho các hành động lặp đi lặp lại.
- Bạn không nên sử dụng hộp thoại modal nếu chúng làm gián đoạn luồng tự nhiên của người dùng trên trang web, đặc biệt nếu nội dung hoặc hành động trong hộp thoại modal không khẩn cấp hoặc quan trọng.
Trước khi bắt đầu
Để theo dõi hướng dẫn này, bạn nên có:
- Kiến thức cơ bản về HTML: Hiểu cách các phần tử và thuộc tính HTML hoạt động.
- Kiến thức cơ bản về JavaScript: Quen thuộc với các khái niệm cơ bản của JavaScript như hàm, xử lý sự kiện và thao tác DOM sẽ rất hữu ích.
- Hiểu biết về ARIA: Mặc dù hướng dẫn giải thích các vai trò và thuộc tính của ARIA, nhưng việc có kiến thức cơ bản về các khái niệm về khả năng truy cập có thể sẽ có lợi.
Nguyên tắc thiết kế hộp thoại Modal dễ tiếp cận
Dưới đây là một số mẹo giúp bạn xây dựng các hộp thoại modal hữu ích và dễ tiếp cận:
- Cung cấp thuộc tính aria-labelledby mô tả trỏ đến tiêu đề hoặc đề mục của hộp thoại modal. Nếu không có tiêu đề, hãy sử dụng aria-label để cung cấp một nhãn mô tả ngắn gọn.
- Luôn bao gồm một nút đóng dễ nhìn và dễ dàng truy cập trong hộp thoại modal, thường ở góc trên cùng bên phải. Dán nhãn rõ ràng cho nút này, ví dụ: bằng văn bản "Đóng" hoặc một biểu tượng có aria-label="Đóng".
- Khi hộp thoại modal mở ra, hãy di chuyển tiêu điểm bàn phím đến phần tử tương tác đầu tiên trong hộp thoại modal (thường là nút đóng). Khi hộp thoại modal đóng lại, hãy trả lại tiêu điểm cho phần tử đã kích hoạt hộp thoại modal.
- Giữ tiêu điểm bàn phím trong hộp thoại modal khi nó đang mở.
- Cho phép người dùng đóng hộp thoại modal bằng cách nhấn phím Escape.
Làm theo các hướng dẫn này, chúng ta hãy cùng xây dựng một hộp thoại modal.
Tôi thích sử dụng các thẻ HTML phù hợp để xây dựng các thành phần và trong trường hợp này, tôi sẽ thực hiện chính xác điều đó bằng cách sử dụng thẻ dialog.
Cách xây dựng hộp thoại Modal sử dụng thẻ dialog
Trong trường hợp bạn chưa quen với thẻ dialog, nó đã được giới thiệu trong HTML5. Bạn sử dụng nó để tạo các hộp thoại như cửa sổ bật lên, cảnh báo và hộp thoại modal. Nó cung cấp các phương thức và thuộc tính tích hợp sẵn giúp quản lý hành vi của hộp thoại dễ dàng hơn mà không cần JavaScript mở rộng. Các phương thức tích hợp sẵn của javascript là show(), showModal() và close().
show() và showModal()
Phương thức show() hữu ích cho hộp thoại không chặn. Điều này có nghĩa là hộp thoại xuất hiện trên đầu nội dung hiện tại, nhưng người dùng vẫn có thể tương tác với các phần khác của trang web (nhấp vào nút, liên kết, v.v.) trong khi hộp thoại đang mở. Điều này hữu ích trong các trường hợp hộp thoại cung cấp thông tin không yêu cầu người dùng phải chú ý ngay lập tức. Dưới đây là một ví dụ:
<!-- Previous content here -->
<dialog id="dialog-box">
<!-- More content here -->
</dialog> <script> const dialog = document.getElementById('dialog-box'); dialog.show();
</script>
Kết quả:
Phương thức showModal() mở hộp thoại ở chế độ modal. Điều này có nghĩa là hộp thoại sẽ lấy tiêu điểm và việc tương tác với phần còn lại của trang web sẽ bị chặn cho đến khi hộp thoại bị đóng. Người dùng không thể nhấp vào hoặc tương tác với bất kỳ phần nào khác của trang. Tùy thuộc vào trình duyệt, phông nền bán trong suốt sẽ xuất hiện phía sau hộp thoại, cho biết trực quan rằng phần còn lại của trang không thể tương tác.
Khi hộp thoại được mở bằng showModal(), tiêu điểm sẽ tự động bị giữ lại trong hộp thoại. Người dùng chỉ có thể tab qua các phần tử bên trong hộp thoại và tiêu điểm sẽ lặp lại trong nội dung của hộp thoại cho đến khi nó bị đóng. Dưới đây là một ví dụ:
<dialog id="dialog-box">
<!-- More content here -->
</dialog> <script> const dialog = document.getElementById('dialog-box'); dialog.showModal();
</script>
Kết quả:
Phần tử <dialog> có kiểu dáng mặc định nhưng có thể được tùy chỉnh bằng CSS để phù hợp với thiết kế của bạn. Bạn có thể tạo kiểu cho hộp thoại, thêm hoạt ảnh hoặc sửa đổi phông nền.
Phông nền có thể được tạo kiểu bằng cách sử dụng bộ chọn ::backdrop. Ví dụ:
dialog::backdrop { background: rgba(0, 0, 0, 0.7);
}
Hộp thoại cũng đi kèm với một số tính năng trợ năng tích hợp sẵn như quản lý tiêu điểm, phông nền, thông báo tự động khi mở và nhấn phím ESC sẽ đóng hộp thoại.
Bạn có thể thêm thuộc tính autofocus vào phần tử tương tác đầu tiên trong hộp thoại modal, chẳng hạn như đầu vào đầu tiên trong biểu mẫu hoặc nút đóng. Ngoài ra, bạn có thể dựa vào khả năng quản lý tiêu điểm gốc của phần tử <dialog>.
Tránh sử dụng tabindex trên phần tử <dialog>, vì nó không phải là phần tử tương tác như nút hoặc liên kết. <dialog> đóng vai trò là bộ chứa cho nội dung tương tác và nó không nhằm mục đích nhận tiêu điểm trực tiếp của người dùng.
Phần tử <dialog> cung cấp một cách nguyên bản để tạo hộp thoại modal. Nếu bạn đang xây dựng một hộp thoại modal tùy chỉnh, hãy đảm bảo các tính năng trợ năng của nó phù hợp với các tính năng của phần tử <dialog> gốc.
Kết hợp tất cả lại với nhau:
<style> dialog::backdrop { background: rgba(0, 0, 0, 0.7); }
</style>
<body> <button id="open-dialog">Open Dialog</button> <dialog id="dialog-box"> <h2>Modal title</h2> <div> <!-- More content here --> <button id="close-dialog" autofocus>Close</button> </div> </dialog> <script> const dialog = document.getElementById("dialog-box"); const openButton = document.getElementById("open-dialog"); const closeButton = document.getElementById("close-dialog"); openButton.addEventListener("click", () => { dialog.showModal(); }); closeButton.addEventListener("click", () => { dialog.close(); });
</script>
</body>
Bạn sẽ nhận thấy rằng tôi đã không sử dụng thuộc tính aria-label trên hộp thoại như tôi đã liệt kê trong hướng dẫn. Vâng, đó là bởi vì phần tử hộp thoại, nếu được cấu trúc tốt, không nhất thiết cần một phần tử. Trong trường hợp này, có một nhãn hiển thị trong phần tử hộp thoại (phần tử h2).
Nếu không có nhãn hiển thị nào thì bạn cần thêm một nhãn. Giống như trong ví dụ này:
<dialog id="confimation-dialog" aria-label="Confirmation Dialog"> <p>Are you sure you want to proceed?</p> <button id="close-dialog" autofocus>Close</button>
</dialog>
Thuộc tính inert là gì?
Khi hộp thoại modal được mở, trình đọc màn hình có thể vẫn điều hướng đến và xung quanh nội dung bên ngoài hộp thoại modal. Bạn thường muốn tiêu điểm của người dùng bị giới hạn trong chính hộp thoại modal hoặc ngăn người dùng vô tình nhấp vào các phần tử bên ngoài hộp thoại modal để ngăn ngừa nhầm lẫn và lỗi. Trong những trường hợp này, bạn sẽ cần thuộc tính inert.
Thuộc tính inert làm cho một phần tử và tất cả các phần tử con của nó không thể tương tác và không thể truy cập được đối với các công nghệ hỗ trợ. Khi hộp thoại modal được mở, việc sử dụng thuộc tính inert trên phần còn lại của nội dung trang sẽ đảm bảo rằng chỉ nội dung hộp thoại modal có thể được truy cập, giúp trải nghiệm hộp thoại rõ ràng hơn.
Cách sử dụng thuộc tính inert
Khi hộp thoại modal được mở, bạn có thể áp dụng thuộc tính inert cho phần còn lại của nội dung trang (thường là phần tử <main>). Khi hộp thoại modal bị đóng, bạn hãy xóa thuộc tính inert.
Dưới đây là một ví dụ cho thấy cách sử dụng inert với hộp thoại modal:
<body> <header>Site Header</header> <main id="main-content"> <button id="open-dialog">Open modal</button> <p>This is the main content of the page.</p> <!-- More content here --> </main> <!-- Move the dialog outside the main element --> <dialog id="dialog"> <h2>Modal Title</h2> <p>This is the content inside the modal.</p> <button id="close-dialog" autofocus>Close</button> </dialog> <script> const dialog = document.getElementById('dialog'); const mainContent = document.getElementById('main-content'); const openButton = document.getElementById('open-dialog'); const closeButton = document.getElementById('close-dialog'); openButton.addEventListener("click", () => { mainContent.setAttribute('inert', ''); dialog.showModal(); }); closeButton.addEventListener("click", () => { dialog.close(); }); // the dialog elemnt has a close event, which is called when a user calls the close() method or presses the esc key dialog.addEventListener("close", (event) => { mainContent.removeAttribute("inert"); }); </script>
</body>
Cách tạo hoạt ảnh cho trạng thái Mở Và Đóng
Khi hộp thoại modal xuất hiện (trạng thái mở) hoặc biến mất (trạng thái đóng), người dùng có thể cảm thấy khó chịu nếu quá trình chuyển đổi này diễn ra đột ngột. Tạo hoạt ảnh cho các trạng thái này có thể tạo ra trải nghiệm người dùng mượt mà hơn bằng cách dần dần đưa vào hoặc loại bỏ hộp thoại modal, tạo cảm giác tự nhiên hơn.
Tại sao nên tạo hoạt ảnh cho trạng thái mở và đóng?
Việc tạo hoạt ảnh cho trạng thái mở và đóng của hộp thoại modal có thể:
- Nâng cao Trải nghiệm Người dùng: Hoạt ảnh mượt mà có thể làm cho quá trình chuyển đổi ít đột ngột hơn và hấp dẫn hơn.
- Thu hút Sự chú ý: Hoạt ảnh tinh tế có thể giúp hướng dẫn sự tập trung của người dùng vào nội dung hộp thoại modal khi nó xuất hiện.
- Duy trì Tính nhất quán: Hoạt ảnh nhất quán trên giao diện người dùng của bạn có thể tạo ra cảm giác gắn kết và chuyên nghiệp.
Theo mặc định, hộp thoại được đặt thành display:none khi đóng và display:block khi mở. Bạn không thể chuyển đổi từ none sang block trong CSS, nhưng bạn có thể kết hợp các thuộc tính hiển thị với transform hoặc opacity. Thuộc tính transform có thể được sử dụng để chia tỷ lệ hoặc di chuyển hộp thoại modal, trong khi opacity kiểm soát độ trong suốt của nó.
Dưới đây là ví dụ về cách bạn có thể tạo hoạt ảnh cho hộp thoại modal:
dialog { animation: zoom-out 0.5s ease-out;
} /* an open attribute is added to the dialog when it is open */
dialog[open] { animation: zoom-in 0.5s ease-out;
} /* The display property in the keyframes is critical because it toggles the modal’s visibility on and off. */
@keyframes zoom-in { 0% { opacity: 0; transform: scale(0.1); display: none; } 100% { opacity: 1; transform: scale(1); display: block; }
} @keyframes zoom-out { 0% { opacity: 1; transform: scale(1); display: block; } 100% { opacity: 0; transform: scale(0); display: none; }
}
Kết quả cuối cùng:
Kết luận
Phần tử <dialog> là cách nguyên bản để tạo hộp thoại modal. Nó cung cấp các tính năng trợ năng tích hợp sẵn cho cả người dùng bàn phím và trình đọc màn hình.
Phần tử <dialog> có hai loại, modal và phi modal. Bạn có thể tạo hộp thoại phi modal bằng cách sử dụng phương thức show() và phương thức showModal() sẽ tạo hộp thoại modal.
Khi bạn không sử dụng phần tử hộp thoại gốc, hãy đảm bảo hộp thoại modal tùy chỉnh của bạn khớp với hộp thoại gốc về khả năng truy cập để đảm bảo trải nghiệm đồng nhất cho tất cả người dùng.
Bạn cũng nên luôn nhớ tự động lấy nét phần tử tương tác ngay lập tức nhất, hộp thoại có thể thực hiện việc này theo mặc định.
Cuối cùng, bạn có thể sử dụng thuộc tính inert trên các phần tử khác để ngăn các phần tử đó được truy cập khi hộp thoại modal đang mở.