Ngăn trang bên dưới hộp thoại phương thức cuộn

Khi một phần tử <dialog> được mở dưới dạng phương thức bằng showModal(), trình duyệt sẽ đưa phần tử đó lên lớp trên cùng và đánh dấu phần còn lại của tài liệu là không hoạt động. Mặc dù thao tác này chặn các lượt nhấp bằng con trỏ và tiêu điểm bàn phím trên trang bên dưới, nhưng không ngăn được thao tác cuộn:

  1. Thao tác cuộn trong khi con trỏ hoặc cử chỉ chạm đang ở trên ::backdrop sẽ cuộn trang bên dưới.
  2. Thao tác cuộn bên trong <dialog> sẽ chuyển sang trang bên dưới khi hộp thoại đạt đến ranh giới cuộn hoặc ngay lập tức nếu nội dung của hộp thoại không bị tràn.

Theo thông số kỹ thuật của Hành vi cuộn quá mức CSS, overscroll-behavior áp dụng cho tất cả phần tử vùng chứa cuộn, bao gồm cả vùng chứa cuộn không thể cuộn (các phần tử có overflow: hidden hoặc overflow: auto có nội dung hiện không bị tràn). Bằng cách kết hợp overscroll-behavior: contain trên <dialog> với overflow: hidden và overscroll-behavior: contain trên dialog::backdrop, bạn có thể ngăn trang bên dưới cuộn bằng CSS thuần tuý.

Triển khai

1. Chứa chuỗi cuộn trên <dialog>

Biểu định kiểu tác nhân người dùng đặt overflow: auto trên <dialog>, khiến biểu định kiểu này trở thành vùng chứa cuộn theo mặc định. Áp dụng overscroll-behavior: contain (hoặc none) cho dialog:modal (hoặc dialog).

2. Biến ::backdrop thành vùng chứa cuộn và chứa thao tác cuộn của vùng chứa đó

Theo mặc định, dialog::backdrop có overflow: visible, nghĩa là đây không phải là vùng chứa cuộn và bỏ qua overscroll-behavior. Bạn phải đặt overflow: hidden trên dialog::backdrop để biến vùng chứa này thành vùng chứa cuộn không thể cuộn và ghép nối vùng chứa này với overscroll-behavior: contain để các cử chỉ cuộn được thực hiện trên phông nền bị chặn và không đến được tài liệu bên dưới.

Mã ví dụ

dialog:modal {
  /* MANDATORY: Prevent scroll gestures inside the modal (even when its content
     does not overflow) from chaining to the underlying page. */
  overscroll-behavior: contain;
}

dialog::backdrop {
  /* MANDATORY: ::backdrop defaults to overflow: visible (not a scroll container).
     Set overflow: hidden so it becomes a non-scrollable scroll container that
     honors overscroll-behavior. */
  overflow: hidden;
  overscroll-behavior: contain;
}

Các phương pháp hay nhất và quy tắc ràng buộc

  • BẮT BUỘC: Đặt overscroll-behavior: contain trên chính phần tử <dialog> (bằng cách sử dụng bộ chọn dialog:modal) và dialog::backdrop. Nếu không có nội dung khai báo này, thì cử chỉ cuộn trên phông nền hoặc bên trong hộp thoại vẫn sẽ liên kết với trang.
  • BẮT BUỘC: Đặt overflow: hidden (hoặc overflow: auto) trên dialog::backdrop để biến thành vùng chứa cuộn. Nếu không có nội dung khai báo này, ::backdrop sẽ mặc định là overflow: visible và overscroll-behavior sẽ không có hiệu lực.
  • KHÔNG sử dụng overflow: clip hoặc overflow: visible trên dialog::backdrop hoặc dialog. Cả hai giá trị đều không thiết lập vùng chứa cuộn, vì vậy, overscroll-behavior sẽ không áp dụng.
  • KHÔNG áp dụng overflow: hidden hoặc position: fixed cho <html> hoặc <body> để khoá thao tác cuộn trong nền khi hộp thoại mở ra. Việc thay đổi thuộc tính tràn của phần tử gốc sẽ xoá thanh cuộn trang (gây ra sự thay đổi bố cục theo chiều ngang), có thể đặt lại hoặc nhảy vị trí cuộn trang và có thể làm hỏng các phần tử position: sticky trên trang cơ bản.

Chiến lược dự phòng

Mặc dù thuộc tính CSS overscroll-behavior được hỗ trợ trên tất cả các trình duyệt chính cho vùng chứa cuộn có nội dung bị tràn, nhưng việc tuân thủ overscroll-behavior trên vùng chứa cuộn không thể cuộn là một thông số kỹ thuật mới hơn không thể phát hiện tính năng.

KHÔNG cố gắng phát hiện tính năng hỗ trợ vùng chứa không thể cuộn bằng @supports (overscroll-behavior: contain) hoặc CSS.supports('overscroll-behavior', 'contain'). Tất cả trình duyệt hiện đại đều hỗ trợ cú pháp thuộc tính overscroll-behavior: contain và trả về true, ngay cả khi các trình duyệt này chỉ thực thi cú pháp đó khi nội dung bị tràn.

Thay vào đó, hãy coi việc chứa cuộn trên các vùng chứa cuộn không thể cuộn là một cải tiến tăng dần:

  • Trong các trình duyệt hỗ trợ overscroll-behavior trên vùng chứa cuộn không thể cuộn, thao tác cuộn trang nền sẽ bị chặn hoàn toàn cả trên dialog::backdrop và bên trong <dialog> (cho dù nội dung của vùng chứa đó có bị tràn hay không).
  • Trong các trình duyệt chưa hỗ trợ overscroll-behavior trên vùng chứa cuộn không thể cuộn, overscroll-behavior: contain trên dialog vẫn ngăn chặn chuỗi cuộn bất cứ khi nào nội dung của hộp thoại bị tràn và có thể cuộn. Trong khi đó, showModal() vẫn giữ tiêu điểm bàn phím và đánh dấu tài liệu nền inert.
  • Bạn nên dựa vào tính năng cải tiến tăng dần thay vì các giải pháp cũ áp dụng overflow: hidden hoặc position: fixed cho <html> hoặc <body>, vì tính năng này không xoá thanh cuộn gốc, không gây ra sự thay đổi bố cục theo chiều ngang, không làm thay đổi vị trí cuộn trang hoặc không làm hỏng các phần tử position: sticky trên trang cơ bản.