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, làm gián đoạn người dùng trên một trang web. Mặc dù có một số trường hợp sử dụng hợp lệ cho việc bật lên hộp thoại, nhưng bạn nên cân nhắc kỹ trước khi thêm hộp thoại. Hộp thoại phương thức buộc người dùng phải tập trung vào nội dung cụ thể và tạm thời bỏ qua phần còn lại của trang.

Hộp thoại có thể là:

  • Hộp thoại phụ thuộc: Người dùng chỉ có thể tương tác với nội dung trong hộp thoại. Hộp thoại phương thức được hiển thị ở đầu nội dung trang. Trang được đặt thành inert và theo mặc định, trang sẽ bị che khuất bởi một phông nền bán trong suốt.
  • Không có phương thức: Người dùng có thể tương tác với nội dung bên ngoài hộp thoại.

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

Hãy xem ví dụ về một <dialog> phương thức. Nhấp vào Mở hộp thoại phương thức. Sau khi mở, có 3 cách để đóng hộp thoại: phím thoát, gửi biểu mẫu bằng nút có đặt 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ó ba 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 */

Vì <dialog> này được mở bằng phương thức HTMLDialogElement.showModal() nên đây là một hộp thoại phụ thuộc. Khi mở hộp thoại phương thức, mọi thứ khác ngoài hộp thoại đó sẽ bị vô hiệu hoá và che khuất. Khi bạn di chuột qua giao diện người dùng bên ngoài hộp thoại, tất cả các thành phần sẽ hoạt động như thể pointer-events: none; đã được đặt. Ngay cả nút mở hộp thoại cũng sẽ không phản ứng với các lượt tương tác.

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

Khi hộp thoại đóng, dù là hộp thoại phụ hay không, tiêu điểm sẽ được trả về phần tử đã mở hộp thoại. Tránh mở hộp thoại theo phương thức lập trình mà không có hành động của người dùng. Nếu bắt buộc, hãy đảm bảo rằng bạn trả tiêu điểm về vị trí trước khi mở hộp thoại, đặ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 đó.

Có một thuộc tính inert chung có thể dùng để tắt một phần tử và tất cả phần tử con của phần tử đó, ngoại trừ mọi hộp thoại đang hoạt động. Khi một hộp thoại phụ được mở bằng showModal(), trạng thái không hoạt động hoặc huỷ kích hoạt sẽ xảy ra theo mặc định. Thuộc tính này 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ứ ngoài hộp thoại bằng cách sử dụng phần tử giả ::backdrop. Phông nền chỉ xuất hiện khi <dialog> xuất hiện cùng với 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 hiển thị khi sử dụng FullScreen API, 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.

Hộp thoại không phụ thuộc

HTMLDialogElement.show() cũng mở một hộp thoại, nhưng không thêm phông nền hoặc khiến bất kỳ thành phần nào trở nên không hoạt động. Phím thoát chỉ đóng hộp thoại phương thức, chứ không đóng hộp thoại không theo phương thức. Do đó, việc thêm một phương thức đóng hộp thoại không phụ thuộc càng quan trọng hơn. Nếu lựa chọn đóng nằm ngoài hộp thoại, thì tiêu điểm sẽ quay lại phần tử đã mở hộp thoại. Đây là trải nghiệm người dùng không lý tưởng.

Mặc dù nút đóng hộp thoại không bắt buộc theo quy cách, nhưng bạn nên coi nút này là bắt buộc. Một nút hiển thị có thể nhận tiêu điểm sẽ 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ần 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 bằng phương thức dialog, trạng thái của dữ liệu do người dùng nhập sẽ được duy trì. Khi có sự kiện gửi, biểu mẫu sẽ trải qua quy trình xác thực quy tắc ràng buộc (trừ phi bạn đặt novalidate). Dữ liệu người dùng không bị xoá hoặc gửi. Bạn có thể tạo nút đóng mà không cần JavaScript:

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

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

Khi một hộp thoại được mở, phần tử có thể làm tâm điểm đầu tiên trong hộp thoại sẽ nhận được tâm điểm, trừ phi một phần tử khác có thuộc tính autofocus. Việc đặt thuộc tính autofocus trên nút đóng sẽ đảm bảo nút này nhận được tiêu điểm khi hộp thoại mở ra. Tuy nhiên, bạn chỉ nên đưa autofocus vào <dialog> sau khi cân nhắc kỹ lưỡng. Tất cả các 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 thêm về thuộc tính này trong mô-đun tiêu điểm.

Giao diện HTMLDialogElement bao gồm thuộc tính returnValue. Việc gửi biểu mẫu có method="dialog" sẽ đặt 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>, thì 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ể 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ì bằng .show() hoặc .showModal(), thì 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 là hộp thoại có phải là phương thức hay không.

Mặc dù JavaScript là phương thức ưu tiên để mở hộp thoại, nhưng việc thêm thuộc tính open khi tải trang rồi xoá thuộc tính đó bằng .close() có thể giúp đảm bảo hộp thoại luô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 có trong hộp thoại (và có thể là nội dung khác) có thể nhận tiêu điểm và có tính tương tác. Phần tử <dialog> không có tính tương tác và không nhận 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 định là dialog. Nếu hộp thoại là một cửa sổ xác nhận truyền đạt thông báo yêu cầu người dùng phản hồi hoặc xác nhận, hãy đặt role="alertdialog". Thêm tên thành phần hỗ trợ tiếp cận cho hộp thoại. 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".

CSS mặc định

Trình duyệt cung cấp kiểu mặc định cho dialog. Firefox, Chrome và Edge đặt color: CanvasText; và background-color: Canvas;. 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, thay vì body hoặc :root, điều này có thể không mong muốn. Thuộc tính background-color không được kế thừa.

Kiểm tra kiến thức của bạn

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

Làm cách nào để tạo kiểu cho khu vực phía sau hộp thoại?

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