Hộp thoại

Hộp thoại phương thức là một loại hộp bật lên đặc biệt trên trang web: một cửa sổ bật lên làm gián đoạn quá trình người dùng tập trung vào chính nó. Có một số trường hợp sử dụng hợp lệ để bật hộp thoại, nhưng bạn nên cân nhắc kỹ trước khi thực hiện. Hộp thoại phương thức buộc người dùng tập trung vào nội dung cụ thể và tạm thời ít nhất là bỏ qua phần còn lại của trang.

Hộp thoại có thể là phương thức (chỉ có thể tương tác với nội dung trong hộp thoại) hoặc không phương thức (bạn vẫn có thể tương tác với nội dung bên ngoài hộp thoại). Hộp thoại phương thức hiển thị ở đầu phần nội dung còn lại của trang. Phần còn lại của trang là trần và theo mặc định, bị che khuất bởi phông nền bán trong suốt.

Phần tử HTML ngữ nghĩa <dialog> để tạo hộp thoại đi kèm với ngữ nghĩa, hoạt động tương tác bằng bàn phím, cũng như tất cả thuộc tính và phương thức của giao diện HTMLDialogElement.

Dưới đây là ví dụ về một phương thức <dialog>. Mở hộp thoại có nút "Mở hộp thoại phương thức". Sau khi mở hộp thoại, có 3 cách để đóng hộp thoại: phím thoát, gửi biểu mẫu bằng một nút có tập hợp formmethod="dialog" (hoặc nếu chính biểu mẫu đó đã được đặt method="dialog") và phương thức HTMLDialogElement.close().

HTMLDialogElement có 3 phương thức chính, cùng với tất cả các phương thức kế thừa từ HTMLElement.

dialog.show() /* opens the dialog */
dialog.showModal() /* opens the dialog as a modal */
dialog.close() /* closes the dialog */

<dialog> này đã được mở thông qua phương thức HTMLDialogElement.showModal() nên đây là một hộp thoại phương thức. Việc mở hộp thoại phương thức sẽ huỷ kích hoạt và che khuất mọi thứ ngoài chính hộp thoại đó. Nếu di chuột qua giao diện người dùng bên ngoài hộp thoại, bạn sẽ thấy tất cả các thành phần đều hoạt động như thể pointer-events: none; đã được đặt; ngay cả nút mở hộp thoại cũng không phản ứng với các hoạt động tương tác.

Khi hộp thoại được mở, tiêu điểm sẽ di chuyển vào hộp thoại. Tiêu điểm được đặt trên phần tử đầu tiên trong thứ tự điều hướng bàn phím tuần tự trong hộp thoại đó. Nếu bạn nhấn phím tab nhiều lần, bạn sẽ lưu ý rằng chỉ nội dung trong hộp thoại mới có thể lấy tiêu điểm khi hộp thoại phương thức đang mở. Mọi thứ bên ngoài hộp thoại phương thức đều ở trạng thái tĩnh miễn là hộp thoại đó đang mở.

Khi bạn đóng hộp thoại, dù là chế độ hay không, tiêu điểm sẽ được trả về phần tử đã mở hộp thoại đó. Nếu bạn mở một hộp thoại theo phương thức lập trình không dựa trên thao tác của người dùng, hãy xem xét lại. Nếu cần, hãy đảm bảo rằng tiêu điểm được đặt lại vị trí trước khi hộp thoại mở, đặc biệt là nếu người dùng đóng hộp thoại mà không tương tác với hộp thoại đó.

Ngoại trừ hộp thoại đang hoạt động, có một thuộc tính inert chung có thể dùng để vô hiệu hoá một phần tử và tất cả các thành phần con cháu. Khi một hộp thoại phương thức được mở bằng showModal(), tính năng trơ hoặc huỷ kích hoạt sẽ miễn phí; thuộc tính không được đặt rõ ràng.

Bạn có thể tạo kiểu cho phông nền che khuất mọi thứ khác ngoài hộp thoại bằng phần tử giả ::backdrop. Phông nền chỉ hiển thị khi <dialog> được hiển thị bằng phương thức .showModal(). Phần tử giả này khớp với tất cả phông nền, bao gồm cả phông nền được hiển thị khi sử dụng API FullScreen, chẳng hạn như khi xem video ở chế độ toàn màn hình không có cùng tỷ lệ khung hình với màn hình hoặc màn hình.

Hộp thoại không phải là phương thức

Tương tự như vậy, HTMLDialogElement.show() sẽ mở ra một hộp thoại, nhưng không thêm phông nền hoặc khiến bất kỳ nội dung nào trở nên trơ. Phím Escape không đóng các hộp thoại không phải là phương thức. Do đó, điều quan trọng hơn là bạn phải đưa vào một phương thức để đóng hộp thoại không thuộc phương thức. Khi đó, nếu ở gần hơn ở bên ngoài hộp thoại, hãy lưu ý rằng tiêu điểm sẽ chuyển đến phần tử đã mở hộp thoại. Đây có thể không phải là trải nghiệm tốt nhất cho người dùng.

Mặc dù bản đặc tả không chính thức yêu cầu nút đóng hộp thoại, nhưng hãy coi việc đó là bắt buộc. Khoá thoát sẽ đóng hộp thoại phương thức, nhưng không đóng hộp thoại không có phương thức. Một nút hiển thị có thể nhận tiêu điểm sẽ giúp cải thiện khả năng hỗ trợ tiếp cận và trải nghiệm người dùng.

Đóng hộp thoại

Bạn không cần phương thức HTMLDialogElement.close() để đóng hộp thoại. Bạn hoàn toàn không cần JavaScript. Để đóng <dialog> mà không có JavaScript, hãy thêm một biểu mẫu có phương thức hộp thoại bằng cách đặt method="dialog" trên <form> hoặc formmethod="dialog" trên nút.

Khi người dùng gửi thông qua phương thức dialog, trạng thái của dữ liệu do người dùng nhập vẫn được duy trì. Mặc dù có sự kiện gửi – biểu mẫu sẽ được xác thực quy tắc ràng buộc (trừ phi bạn đặt novalidate), dữ liệu người dùng sẽ không bị xoá hoặc không được gửi. Nút đóng không có JavaScript có thể được viết là:

<dialog open>
  <form method="dialog">
    <button type="submit" autofocus>close</button>
  </form>
</dialog>

Bạn có thể đã thấy thuộc tính autofocus được đặt trên <button> đóng trong ví dụ này. Các phần tử có thuộc tính autofocus được đặt trong <dialog> sẽ không nhận được tiêu điểm khi tải trang (trừ khi trang được tải với hộp thoại hiển thị). Tuy nhiên, chúng sẽ được lấy tiêu điểm khi hộp thoại mở ra.

Theo mặc định, khi một hộp thoại được mở, phần tử có thể lấy tiêu điểm đầu tiên trong hộp thoại sẽ nhận được tiêu điểm trừ phi một phần tử khác trong hộp thoại đã đặt thuộc tính autofocus. Việc đặt thuộc tính autofocus trên nút đóng đảm bảo thuộc tính này nhận được tiêu điểm khi hộp thoại được mở. Tuy nhiên, bạn chỉ nên cân nhắc kỹ khi đưa autofocus vào <dialog>. Mọi phần tử trong trình tự đứng trước phần tử được lấy tiêu điểm tự động đều bị bỏ qua. Chúng ta sẽ thảo luận kỹ hơn về thuộc tính này trong bài học tiêu điểm.

Giao diện HTMLDialogElement bao gồm một thuộc tính returnValue. Khi gửi biểu mẫu bằng method="dialog", hệ thống sẽ thiết lập returnValue thành name (nếu có) của nút gửi dùng để gửi biểu mẫu. Nếu chúng ta đã viết <button type="submit" name="toasty">close</button>, returnValue sẽ là toasty.

Khi một hộp thoại được mở, thuộc tính boolean open sẽ xuất hiện, nghĩa là hộp thoại đang hoạt động và có thể được tương tác. Khi một hộp thoại được mở bằng cách thêm thuộc tính open thay vì qua .show() hoặc .showModal(), hộp thoại sẽ không có phương thức. Thuộc tính HTMLDialogElement.open trả về true hoặc false, tuỳ thuộc vào việc hộp thoại có sẵn để tương tác hay không, chứ không phải hộp thoại có phương thức hay không.

Mặc dù JavaScript là phương thức ưu tiên để mở hộp thoại, bao gồm thuộc tính open khi tải trang và sau đó xoá thuộc tính đó bằng .close(), có thể giúp đảm bảo hộp thoại vẫn có sẵn ngay cả khi không có JavaScript.

Thông tin khác

Không sử dụng tabindex

Phần tử được kích hoạt để mở hộp thoại và nút đóng chứa trong đó (và có thể là cả nội dung khác) có thể nhận được tiêu điểm và có khả năng tương tác. Phần tử <dialog> không tương tác và không nhận được tiêu điểm. Đừng thêm thuộc tính tabindex vào chính hộp thoại.

Vai trò ARIA

Vai trò ngầm ẩn là dialog. Nếu hộp thoại là cửa sổ xác nhận truyền đạt một thông báo quan trọng yêu cầu xác nhận hoặc phản hồi khác của người dùng, hãy đặt role="alertdialog". Hộp thoại cũng phải có tên thành phần hỗ trợ tiếp cận. Nếu văn bản hiển thị có thể cung cấp tên thành phần hỗ trợ tiếp cận, hãy thêm aria-labelledby="idOfLabelingText".

Dịch vụ so sánh giá mặc định

Xin lưu ý rằng các trình duyệt cung cấp kiểu mặc định cho dialog. Firefox, Chrome và Edge đặt color: CanvasText; background-color: Canvas; và Safari đặt color: black; background-color: white; trong biểu định kiểu tác nhân người dùng. color được kế thừa từ dialog chứ không phải từ body hoặc :root. Điều này có thể gây bất ngờ. Thuộc tính background-color không được kế thừa.

Kiểm tra mức độ hiểu biết của bạn

Kiểm tra kiến thức của bạn về phần tử hộp thoại.

Bạn tạo kiểu cho khu vực phía sau hộp thoại như thế nào?

Với phần tử giả ::background.
Hãy thử lại.
Với phần tử giả ::backdrop.
Chính xác!
Với thuộc tính background.
Hãy thử lại.